mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-11-01 02:28:05 +00:00
Compare commits
404 Commits
v1.1
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
049b077ee4 | ||
|
|
ab2080a805 | ||
|
|
8ab54e76df | ||
|
|
0465397b1d | ||
|
|
d3ec39d506 | ||
|
|
bfe68a5948 | ||
|
|
2ea3363613 | ||
|
|
89cce6e6a3 | ||
|
|
0f10ac706c | ||
|
|
66d26f0ffa | ||
|
|
3c96914482 | ||
|
|
61b1e73362 | ||
|
|
03435079cc | ||
|
|
6661907c1d | ||
|
|
fe811f725c | ||
|
|
f015c6abed | ||
|
|
8598e6591f | ||
|
|
5e2259062c | ||
|
|
d483802a86 | ||
|
|
9a0eece69c | ||
|
|
1657bfd05f | ||
|
|
49bf558916 | ||
|
|
99f44a597b | ||
|
|
71293c1c18 | ||
|
|
bd7c70f902 | ||
|
|
20c92d4338 | ||
|
|
f0158e7202 | ||
|
|
62408ddc98 | ||
|
|
b4f87b36db | ||
|
|
9f49a115a1 | ||
|
|
c7d2305589 | ||
|
|
5826a649de | ||
|
|
fa826391f6 | ||
|
|
3481ba8ee3 | ||
|
|
b4ab0b55de | ||
|
|
0370b45d8a | ||
|
|
468e689094 | ||
|
|
aafd82b16d | ||
|
|
60ee331153 | ||
|
|
3a8ce74355 | ||
|
|
fd44463238 | ||
|
|
a21f3fe6ee | ||
|
|
0ccbb2960c | ||
|
|
84ba2da553 | ||
|
|
e693d96ca1 | ||
|
|
81cb7f8133 | ||
|
|
3471969956 | ||
|
|
7a0985c362 | ||
|
|
b79a9e2e67 | ||
|
|
1e037fe6f5 | ||
|
|
0897be57c1 | ||
|
|
4172b06b19 | ||
|
|
32a4875e46 | ||
|
|
c577a75725 | ||
|
|
8827e0cf6f | ||
|
|
b0012fe399 | ||
|
|
31e634615b | ||
|
|
8300a55e39 | ||
|
|
5b939bc57a | ||
|
|
2f1ab9cc50 | ||
|
|
42ba3eb98d | ||
|
|
9eb87fc8e1 | ||
|
|
8fab9bb945 | ||
|
|
1ead232a78 | ||
|
|
b15c8c60ab | ||
|
|
66bdeb0e4d | ||
|
|
1a2e090104 | ||
|
|
a8e280e29b | ||
|
|
edb54b02ac | ||
|
|
83d3f32fe0 | ||
|
|
085a379592 | ||
|
|
37bd5d0404 | ||
|
|
f788b81d21 | ||
|
|
2ff1ce6b34 | ||
|
|
41a1e40d14 | ||
|
|
921e8d2d3c | ||
|
|
c009d28f7d | ||
|
|
898eada097 | ||
|
|
bdfc55e801 | ||
|
|
57f264bedb | ||
|
|
fbe4fa3cf0 | ||
|
|
b2ef345f35 | ||
|
|
471ea7dfba | ||
|
|
1b52f638ff | ||
|
|
84ab38a75f | ||
|
|
916e5377f8 | ||
|
|
534bfd881e | ||
|
|
7c4015324d | ||
|
|
8499ee52f4 | ||
|
|
cc1123863c | ||
|
|
ca382806f6 | ||
|
|
3559fc61c2 | ||
|
|
33581cdcc9 | ||
|
|
991eb02964 | ||
|
|
286e321a2d | ||
|
|
56f158113d | ||
|
|
024f6ff963 | ||
|
|
8118a0f4f4 | ||
|
|
eb89d8fd86 | ||
|
|
a938c1738b | ||
|
|
4f88882513 | ||
|
|
4e8d8b7ddd | ||
|
|
afb7d75749 | ||
|
|
488d0e1fe8 | ||
|
|
708442e4cd | ||
|
|
a2d905dfb1 | ||
|
|
d564fe3e2a | ||
|
|
ea21cce1c0 | ||
|
|
aa9b4aefbe | ||
|
|
8655030e59 | ||
|
|
8107ddeb79 | ||
|
|
76c8e55f06 | ||
|
|
a7b1ab47d8 | ||
|
|
879f587ab9 | ||
|
|
8af2d80219 | ||
|
|
315eea1f55 | ||
|
|
b61e541e15 | ||
|
|
81f88e78c7 | ||
|
|
87cc3dac00 | ||
|
|
89e28cc7be | ||
|
|
2ba29a78c5 | ||
|
|
f990a6c1be | ||
|
|
424e5a4786 | ||
|
|
6a7a04ebb1 | ||
|
|
0366fc2956 | ||
|
|
48b7d71f02 | ||
|
|
715baf2a1c | ||
|
|
e55cea776e | ||
|
|
b388d143fd | ||
|
|
c592c572d8 | ||
|
|
dfa0a26a28 | ||
|
|
609cd94798 | ||
|
|
022f743db1 | ||
|
|
1957beb1b6 | ||
|
|
9ca72d6105 | ||
|
|
e8e126a6ce | ||
|
|
7849782173 | ||
|
|
149a0da8c9 | ||
|
|
1e7c70a59b | ||
|
|
c9d8282e7f | ||
|
|
e7084a2c29 | ||
|
|
d79d2e0724 | ||
|
|
402155c225 | ||
|
|
e5ec669419 | ||
|
|
8f424e8c9d | ||
|
|
fea2b84bb9 | ||
|
|
0c918940c4 | ||
|
|
a63a6ac0ec | ||
|
|
9f58b914d2 | ||
|
|
029bac4b03 | ||
|
|
a27ad57220 | ||
|
|
8d31d924f2 | ||
|
|
8c3b514f90 | ||
|
|
3df27fe315 | ||
|
|
a6087ce354 | ||
|
|
aae0382523 | ||
|
|
b0c2acb1b5 | ||
|
|
a52c96ae2e | ||
|
|
bf28821b5b | ||
|
|
328bd6ea71 | ||
|
|
ec9eb8d054 | ||
|
|
f8c8526045 | ||
|
|
d8c236bb44 | ||
|
|
33ff0910b8 | ||
|
|
faa69917d9 | ||
|
|
d9f5ca9827 | ||
|
|
c817ef7335 | ||
|
|
07de489d6b | ||
|
|
acafc78456 | ||
|
|
325721545e | ||
|
|
dbe2bf560c | ||
|
|
7872cc2203 | ||
|
|
25b4d0e755 | ||
|
|
9af1c90664 | ||
|
|
6b4d44a3f1 | ||
|
|
2faf8d2cdd | ||
|
|
676c94ddf2 | ||
|
|
6f93b64f84 | ||
|
|
54bf426472 | ||
|
|
1862ce9104 | ||
|
|
3771c13d32 | ||
|
|
f1d0230dad | ||
|
|
182929cc96 | ||
|
|
81585c5a86 | ||
|
|
2f52c11589 | ||
|
|
0f4d8573cf | ||
|
|
660b8b3c6e | ||
|
|
71d6a1138c | ||
|
|
a6e741d8fe | ||
|
|
58bcf65cf6 | ||
|
|
27ce55de38 | ||
|
|
36ca22db9b | ||
|
|
33a8de9b39 | ||
|
|
22b76e36db | ||
|
|
528ff31590 | ||
|
|
4d6966cbd3 | ||
|
|
9c9e3be967 | ||
|
|
2dd4745ef7 | ||
|
|
4e786a32b5 | ||
|
|
6ecb2c85e2 | ||
|
|
cd234a909b | ||
|
|
c249f44ea1 | ||
|
|
ed1f51393a | ||
|
|
8bd43130ab | ||
|
|
6c975a53a1 | ||
|
|
8a1001cd40 | ||
|
|
beb2b576aa | ||
|
|
8f3923046b | ||
|
|
88c68d2065 | ||
|
|
8bcde72a10 | ||
|
|
4653dbcf4b | ||
|
|
cde08b32a4 | ||
|
|
2eed891f8d | ||
|
|
c0b84e84c8 | ||
|
|
2c20fd3f9f | ||
|
|
f4db56ca29 | ||
|
|
5b6d58ac7d | ||
|
|
ecb8bd9fbe | ||
|
|
2f9385451f | ||
|
|
1a1346461b | ||
|
|
27dcd29074 | ||
|
|
93986f36c3 | ||
|
|
a6ab8055b1 | ||
|
|
31ea479d7f | ||
|
|
89fb2e047b | ||
|
|
8f705e6173 | ||
|
|
8f735316f5 | ||
|
|
0d7a1871a1 | ||
|
|
33832b3d25 | ||
|
|
4da7f0cc38 | ||
|
|
e29f8485ea | ||
|
|
2da344a563 | ||
|
|
2a0cb8e14f | ||
|
|
e1dc3dc357 | ||
|
|
8259124f73 | ||
|
|
0422956ac6 | ||
|
|
ff82c5171b | ||
|
|
f9bd6310f1 | ||
|
|
471eab126e | ||
|
|
6ad011d12d | ||
|
|
561c8aff85 | ||
|
|
5cf5dd2234 | ||
|
|
fb9915d301 | ||
|
|
7ab67194d6 | ||
|
|
603ac9d8c5 | ||
|
|
a3c7811e9d | ||
|
|
a3778dfe8b | ||
|
|
2dff934612 | ||
|
|
89d666948e | ||
|
|
c3499142b0 | ||
|
|
d8feccc715 | ||
|
|
16173355f3 | ||
|
|
f46134fda5 | ||
|
|
bfecff0412 | ||
|
|
168f1891cf | ||
|
|
862845b4ac | ||
|
|
b7a5dbff49 | ||
|
|
5be30d89a7 | ||
|
|
d94dc51d88 | ||
|
|
22acd88d44 | ||
|
|
fd406c106b | ||
|
|
16134b5caf | ||
|
|
2c485efced | ||
|
|
279d08a0e8 | ||
|
|
1d4a8998e1 | ||
|
|
47a41e7980 | ||
|
|
ecfc4a8cb2 | ||
|
|
2d66b6266b | ||
|
|
b7afb5f9d2 | ||
|
|
58c16a59ac | ||
|
|
f09789f5ef | ||
|
|
b2e12cd3e0 | ||
|
|
71b157a8ba | ||
|
|
cb8affe9b2 | ||
|
|
3f7180c706 | ||
|
|
f0bc2dc62f | ||
|
|
9c95fd6b69 | ||
|
|
c0fda8c3a2 | ||
|
|
bac20af381 | ||
|
|
626211a320 | ||
|
|
783aaa8cb4 | ||
|
|
768bd8af19 | ||
|
|
3894f52194 | ||
|
|
dcfa9edb1c | ||
|
|
4ebdb5629c | ||
|
|
75b0668fc2 | ||
|
|
5fe94ed463 | ||
|
|
db21b97603 | ||
|
|
8074d0c548 | ||
|
|
2d611afbb0 | ||
|
|
bc42507724 | ||
|
|
ff82ab5718 | ||
|
|
62fe374e15 | ||
|
|
e519a3bc39 | ||
|
|
4f146d12ee | ||
|
|
46d6074ad5 | ||
|
|
cbb61f1240 | ||
|
|
0e9f3c3576 | ||
|
|
92f11dc075 | ||
|
|
3aa0a0999b | ||
|
|
e86fbcfa5b | ||
|
|
0b2ee6fdaf | ||
|
|
35f3866882 | ||
|
|
d86bea80d3 | ||
|
|
13b4b5072f | ||
|
|
efae43f122 | ||
|
|
45e8c8692b | ||
|
|
f8fc2a5050 | ||
|
|
3c20d57cc4 | ||
|
|
2cb3858330 | ||
|
|
925d36a561 | ||
|
|
0ffaca91cc | ||
|
|
d3a0f1d969 | ||
|
|
37704db583 | ||
|
|
aadd038bbe | ||
|
|
6d601b4267 | ||
|
|
194798d881 | ||
|
|
1a10495645 | ||
|
|
0e2316513e | ||
|
|
72ce4e2fad | ||
|
|
4ad7311e18 | ||
|
|
fa2b0e8fad | ||
|
|
78eb926693 | ||
|
|
3613efbaab | ||
|
|
2e732854b3 | ||
|
|
f9560d6b1d | ||
|
|
51b0826398 | ||
|
|
af0adb454d | ||
|
|
cdd4c571b0 | ||
|
|
9c440764c7 | ||
|
|
6e94834033 | ||
|
|
1720ed23c9 | ||
|
|
137fab1d92 | ||
|
|
0fee63fa81 | ||
|
|
d5f0d80eed | ||
|
|
b7d4d43f56 | ||
|
|
c0379a1981 | ||
|
|
e5db8e42d1 | ||
|
|
27cf9806f0 | ||
|
|
5dbb5cd112 | ||
|
|
af75569eb8 | ||
|
|
aebf2ff270 | ||
|
|
3bcdeda3e9 | ||
|
|
7433667243 | ||
|
|
d7c009167f | ||
|
|
79f198d6fe | ||
|
|
315a12b9df | ||
|
|
e14d145f2c | ||
|
|
f839da39f0 | ||
|
|
45ca7a63ed | ||
|
|
5d187255ae | ||
|
|
7adf6aed59 | ||
|
|
b22a7a0234 | ||
|
|
8805723114 | ||
|
|
88db4358f5 | ||
|
|
a5d9685caf | ||
|
|
94ff8e6beb | ||
|
|
f3400d9bc1 | ||
|
|
6a6591e41d | ||
|
|
a3a53f3b06 | ||
|
|
2f39abfdb8 | ||
|
|
92239d66fc | ||
|
|
178813806f | ||
|
|
265dbffc53 | ||
|
|
a67a08a4d0 | ||
|
|
6d15f55304 | ||
|
|
0dbcd1f265 | ||
|
|
a0f6380f90 | ||
|
|
ab69cf5bf4 | ||
|
|
3e55a5526a | ||
|
|
b6216bb701 | ||
|
|
fa3ea3aaa7 | ||
|
|
7b56e3a6c3 | ||
|
|
00ad542a11 | ||
|
|
c3e00eea2c | ||
|
|
5c8dd911e3 | ||
|
|
407fd62da5 | ||
|
|
c92f7ca0d8 | ||
|
|
676901e113 | ||
|
|
c099b53a03 | ||
|
|
fd065e4e7c | ||
|
|
fd97527561 | ||
|
|
7b9647a063 | ||
|
|
bf943f1347 | ||
|
|
dbff610d77 | ||
|
|
46aae9486e | ||
|
|
70066de390 | ||
|
|
106af9d444 | ||
|
|
f0be267f9f | ||
|
|
edbaec7265 | ||
|
|
f4537a538b | ||
|
|
d6eb6f33d2 | ||
|
|
7a139c261a | ||
|
|
2e7aa213ed | ||
|
|
d9344287e4 | ||
|
|
b9768a81e9 | ||
|
|
3418c07512 | ||
|
|
5f8621c224 | ||
|
|
c05f3555a3 | ||
|
|
f21827395b | ||
|
|
894c7bb17a | ||
|
|
2028cfae4d | ||
|
|
2064f65c04 | ||
|
|
1de4a4eaa2 |
1
.codecov.yml
Normal file
1
.codecov.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
comment: off
|
||||||
3
.docker-entry.sh
Executable file
3
.docker-entry.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cp -nr /oopt-gnpy/examples /shared
|
||||||
|
exec "$@"
|
||||||
52
.docker-travis.sh
Executable file
52
.docker-travis.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
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}
|
||||||
|
else
|
||||||
|
echo "Image ${IMAGE_NAME}:${IMAGE_TAG} already available, will just update the other tags"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker images
|
||||||
|
|
||||||
|
do_docker_login() {
|
||||||
|
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${TRAVIS_PULL_REQUEST}" == "false" ]]; then
|
||||||
|
if [[ "${TRAVIS_BRANCH}" == "develop" || "${TRAVIS_BRANCH}" == "docker" ]]; then
|
||||||
|
echo "Publishing latest"
|
||||||
|
docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_NAME}:latest
|
||||||
|
do_docker_login
|
||||||
|
if [[ $ALREADY_FOUND == 0 ]]; then
|
||||||
|
docker push ${IMAGE_NAME}:${IMAGE_TAG}
|
||||||
|
fi
|
||||||
|
docker push ${IMAGE_NAME}:latest
|
||||||
|
elif [[ "${TRAVIS_BRANCH}" == "master" ]]; then
|
||||||
|
echo "Publishing stable"
|
||||||
|
docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_NAME}:stable
|
||||||
|
do_docker_login
|
||||||
|
if [[ $ALREADY_FOUND == 0 ]]; 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
|
||||||
29
.travis.yml
29
.travis.yml
@@ -1,10 +1,27 @@
|
|||||||
|
dist: xenial
|
||||||
|
sudo: false
|
||||||
language: python
|
language: python
|
||||||
|
services: docker
|
||||||
python:
|
python:
|
||||||
- "3.6"
|
- "3.6"
|
||||||
# command to install dependencies
|
- "3.7"
|
||||||
install:
|
install: skip
|
||||||
- python setup.py install
|
|
||||||
# command to run tests
|
|
||||||
before_script:
|
|
||||||
script:
|
script:
|
||||||
- pytest
|
- python setup.py install
|
||||||
|
- pip install pytest-cov rstcheck
|
||||||
|
- pytest --cov-report=xml --cov=gnpy
|
||||||
|
- rstcheck --ignore-roles cite --ignore-directives automodule --recursive --ignore-messages '(Duplicate explicit target name.*)' .
|
||||||
|
- ./examples/transmission_main_example.py
|
||||||
|
- ./examples/path_requests_run.py
|
||||||
|
- ./examples/transmission_main_example.py examples/raman_edfa_example_network.json --sim examples/sim_params.json --show-channels
|
||||||
|
- sphinx-build docs/ x-throwaway-location
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- stage: test
|
||||||
|
name: Docker image
|
||||||
|
script:
|
||||||
|
- git fetch --unshallow
|
||||||
|
- ./.docker-travis.sh
|
||||||
|
- docker images
|
||||||
|
|||||||
8
.zuul.yaml
Normal file
8
.zuul.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
- project:
|
||||||
|
check:
|
||||||
|
jobs:
|
||||||
|
- noop
|
||||||
|
gate:
|
||||||
|
jobs:
|
||||||
|
- noop
|
||||||
@@ -6,16 +6,24 @@ To learn how to contribute, please see CONTRIBUTING.md
|
|||||||
(*in alphabetical order*)
|
(*in alphabetical order*)
|
||||||
|
|
||||||
- Alessio Ferrari (Politecnico di Torino) <alessio.ferrari@polito.it>
|
- Alessio Ferrari (Politecnico di Torino) <alessio.ferrari@polito.it>
|
||||||
|
- Anders Lindgren (Telia Company) <Anders.X.Lindgren@teliacompany.com>
|
||||||
|
- Andrea d'Amico (Politecnico di Torino) <andrea.damico@polito.it>
|
||||||
- Brian Taylor (Facebook) <briantaylor@fb.com>
|
- Brian Taylor (Facebook) <briantaylor@fb.com>
|
||||||
- David Boertjes (Ciena) <dboertje@ciena.com>
|
- David Boertjes (Ciena) <dboertje@ciena.com>
|
||||||
|
- Diego Landa (Facebook) <dlanda@fb.com>
|
||||||
- Esther Le Rouzic (Orange) <esther.lerouzic@orange.com>
|
- Esther Le Rouzic (Orange) <esther.lerouzic@orange.com>
|
||||||
- Gabriele Galimberti (Cisco) <ggalimbe@cisco.com>
|
- Gabriele Galimberti (Cisco) <ggalimbe@cisco.com>
|
||||||
- Gert Grammel (Juniper Networks) <ggrammel@juniper.net>
|
- Gert Grammel (Juniper Networks) <ggrammel@juniper.net>
|
||||||
- Gilad Goldfarb (Facebook) <giladg@fb.com>
|
- Gilad Goldfarb (Facebook) <giladg@fb.com>
|
||||||
- James Powell (Telecom Infra Project) <james.powell@telecominfraproject.com>
|
- James Powell (Telecom Infra Project) <james.powell@telecominfraproject.com>
|
||||||
|
- Jan Kundrát (Telecom Infra Project) <jan.kundrat@telecominfraproject.com>
|
||||||
- Jeanluc Augé (Orange) <jeanluc.auge@orange.com>
|
- Jeanluc Augé (Orange) <jeanluc.auge@orange.com>
|
||||||
- Jonas Mårtensson (RISE) <jonas.martensson@ri.se>
|
- Jonas Mårtensson (RISE) <jonas.martensson@ri.se>
|
||||||
- Mattia Cantono (Politecnico di Torino) <mattia.cantono@polito.it>
|
- Mattia Cantono (Politecnico di Torino) <mattia.cantono@polito.it>
|
||||||
|
- Miguel Garrich (University Catalunya) <miquel.garrich@upct.es>
|
||||||
|
- Raj Nagarajan (Lumentum) <raj.nagarajan@lumentum.com>
|
||||||
- Roberts Miculens (Lattelecom) <roberts.miculens@lattelecom.lv>
|
- Roberts Miculens (Lattelecom) <roberts.miculens@lattelecom.lv>
|
||||||
|
- Shengxiang Zhu (University of Arizona) <szhu@email.arizona.edu>
|
||||||
|
- Stefan Melin (Telia Company) <Stefan.Melin@teliacompany.com>
|
||||||
- Vittorio Curri (Politecnico di Torino) <vittorio.curri@polito.it>
|
- Vittorio Curri (Politecnico di Torino) <vittorio.curri@polito.it>
|
||||||
- Xufeng Liu (Jabil) <xufeng_liu@jabil.com>
|
- Xufeng Liu (Jabil) <xufeng_liu@jabil.com>
|
||||||
|
|||||||
8
Dockerfile
Normal file
8
Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM python:3.7-slim
|
||||||
|
COPY . /oopt-gnpy
|
||||||
|
WORKDIR /oopt-gnpy
|
||||||
|
RUN python setup.py install
|
||||||
|
WORKDIR /shared
|
||||||
|
ENTRYPOINT ["/oopt-gnpy/.docker-entry.sh"]
|
||||||
|
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
|
||||||
@@ -19,8 +19,8 @@ In order to work the excel file MUST contain at least 2 sheets:
|
|||||||
Nodes sheet
|
Nodes sheet
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Nodes sheet contains seven columns.
|
Nodes sheet contains nine columns.
|
||||||
Each line represents a 'node' (ROADM site or an in line amplifier site ILA)::
|
Each line represents a 'node' (ROADM site or an in line amplifier site ILA or a Fused)::
|
||||||
|
|
||||||
City (Mandatory) ; State ; Country ; Region ; Latitude ; Longitude ; Type
|
City (Mandatory) ; State ; Country ; Region ; Latitude ; Longitude ; Type
|
||||||
|
|
||||||
@@ -38,6 +38,9 @@ Each line represents a 'node' (ROADM site or an in line amplifier site ILA)::
|
|||||||
|
|
||||||
- *Longitude*, *Latitude* are not mandatory. If filled they should contain numbers.
|
- *Longitude*, *Latitude* are not mandatory. If filled they should contain numbers.
|
||||||
|
|
||||||
|
- **Booster_restriction** and **Preamp_restriction** are not mandatory.
|
||||||
|
If used, they must contain one or several amplifier type_variety names separated by ' | '. This information is used to restrict types of amplifiers used in a ROADM node during autodesign. If a ROADM booster or preamp is already specified in the Eqpt sheet , the field is ignored. The field is also ignored if the node is not a ROADM node.
|
||||||
|
|
||||||
**There MUST NOT be empty line(s) between two nodes lines**
|
**There MUST NOT be empty line(s) between two nodes lines**
|
||||||
|
|
||||||
|
|
||||||
@@ -166,6 +169,7 @@ This generates a text file meshTopologyExampleV2_eqt_sheet.txt whose content ca
|
|||||||
- **amp type** is not mandatory.
|
- **amp type** is not mandatory.
|
||||||
If filled it must contain types listed in `eqpt_config.json <examples/eqpt_config.json>`_ in "Edfa" list "type_variety".
|
If filled it must contain types listed in `eqpt_config.json <examples/eqpt_config.json>`_ in "Edfa" list "type_variety".
|
||||||
If not filled it takes "std_medium_gain" as default value.
|
If not filled it takes "std_medium_gain" as default value.
|
||||||
|
If filled with fused, a fused element with 0.0 dB loss will be placed instead of an amplifier. This might be used to avoid booster amplifier on a ROADM direction.
|
||||||
|
|
||||||
- **amp_gain** is not mandatory. It is the value to be set on the amplifier (in dB).
|
- **amp_gain** is not mandatory. It is the value to be set on the amplifier (in dB).
|
||||||
If not filled, it will be determined with design rules in the convert.py file.
|
If not filled, it will be determined with design rules in the convert.py file.
|
||||||
@@ -214,26 +218,6 @@ Service sheet must contain 11 columns::
|
|||||||
|
|
||||||
- ** path bandwidth** is optional. It is the amount of capacity required between source and destination in Gbit/s. Default value is 0.0 Gbit/s.
|
- ** path bandwidth** is optional. It is the amount of capacity required between source and destination in Gbit/s. Default value is 0.0 Gbit/s.
|
||||||
|
|
||||||
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
|
path_requests_run.py
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@@ -247,6 +231,11 @@ path_requests_run.py
|
|||||||
|
|
||||||
A function that computes performances for a list of services provided in the service file (accepts json or excel format.
|
A function that computes performances for a list of services provided in the service file (accepts json or excel format.
|
||||||
|
|
||||||
|
if the service <file.xls> is in xls format, path_requests_run.py converts it to a json file <file_services.json> 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>`_. For PSE use, additional fields with trx type and mode have been added to the te-bandwidth field.
|
||||||
|
|
||||||
|
A template for the json file can be found here: `service_template.json <service_template.json>`_
|
||||||
|
|
||||||
|
|
||||||
If no output file is given, the computation is shown on standard output for demo.
|
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.
|
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.
|
||||||
|
|
||||||
|
|||||||
320
README.rst
320
README.rst
@@ -1,13 +1,19 @@
|
|||||||
|
.. image:: docs/images/GNPy-banner.png
|
||||||
|
:width: 100%
|
||||||
|
:align: left
|
||||||
|
:alt: GNPy with an OLS system
|
||||||
|
|
||||||
====================================================================
|
====================================================================
|
||||||
`gnpy`: mesh optical network route planning and optimization library
|
`gnpy`: mesh optical network route planning and optimization library
|
||||||
====================================================================
|
====================================================================
|
||||||
|
|
||||||
|docs| |build|
|
|docs| |build| |doi|
|
||||||
|
|
||||||
**`gnpy` is an open-source, community-developed library for building route
|
**`gnpy` is an open-source, community-developed library for building route
|
||||||
planning and optimization tools in real-world mesh optical networks.**
|
planning and optimization tools in real-world mesh optical networks.**
|
||||||
|
|
||||||
`gnpy <http://github.com/telecominfraproject/oopt-gnpy>`__ is:
|
`gnpy <http://github.com/telecominfraproject/oopt-gnpy>`__ is:
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
- a sponsored project of the `OOPT/PSE <https://telecominfraproject.com/open-optical-packet-transport/>`_ working group of the `Telecom Infra Project <http://telecominfraproject.com>`_
|
- a sponsored project of the `OOPT/PSE <https://telecominfraproject.com/open-optical-packet-transport/>`_ working group of the `Telecom Infra Project <http://telecominfraproject.com>`_
|
||||||
- fully community-driven, fully open source library
|
- fully community-driven, fully open source library
|
||||||
@@ -18,31 +24,50 @@ planning and optimization tools in real-world mesh optical networks.**
|
|||||||
|
|
||||||
Documentation: https://gnpy.readthedocs.io
|
Documentation: https://gnpy.readthedocs.io
|
||||||
|
|
||||||
|
Get In Touch
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
There are `weekly calls <https://telecominfraproject.workplace.com/events/702894886867547/>`__ about our progress.
|
||||||
|
Newcomers, users and telecom operators are especially welcome there.
|
||||||
|
We encourage all interested people outside the TIP to `join the project <https://telecominfraproject.com/apply-for-membership/>`__.
|
||||||
|
|
||||||
Branches and Tagged Releases
|
Branches and Tagged Releases
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
- the `master <https://github.com/Telecominfraproject/oopt-gnpy/tree/master>`_ branch contains stable, validated code. It is updated from develop on a release schedule determined by the OOPT-PSE Working Group. For more information about the validation process, see: https://github.com/Telecominfraproject/oopt-gnpy/wiki/Testing-for-Quality
|
- all releases are `available via GitHub <https://github.com/Telecominfraproject/oopt-gnpy/releases>`_
|
||||||
|
- the `master <https://github.com/Telecominfraproject/oopt-gnpy/tree/master>`_ branch contains stable, `validated code <https://github.com/Telecominfraproject/oopt-gnpy/wiki/Testing-for-Quality>`_. It is updated from develop on a release schedule determined by the OOPT-PSE Working Group.
|
||||||
- the `develop <https://github.com/Telecominfraproject/oopt-gnpy/tree/develop>`_ branch contains the latest code under active development, which may not be fully validated and tested.
|
- the `develop <https://github.com/Telecominfraproject/oopt-gnpy/tree/develop>`_ branch contains the latest code under active development, which may not be fully validated and tested.
|
||||||
- the `phase-1 <https://github.com/Telecominfraproject/oopt-gnpy/tree/phase-1>`_ branch contains code for Phase I of the OOPT-PSE efforts and is kept only for reference. This branch is unmaintained.
|
|
||||||
|
|
||||||
A brief outline of major (tagged) `gnpy` releases:
|
|
||||||
|
|
||||||
+---------------+-------------+-----------------------------------------------+
|
|
||||||
| release date | version tag | notes |
|
|
||||||
+===============+=============+===============================================+
|
|
||||||
| Jan 30, 2019 | v1.1 | - XLS parser enhancements |
|
|
||||||
| | | - carrier probe feature |
|
|
||||||
| | | - bug fixes |
|
|
||||||
+---------------+-------------+-----------------------------------------------+
|
|
||||||
| Oct 16, 2018 | v1.0 | - first "production"-ready release |
|
|
||||||
| | | - open network element model (EDFA, GN-model) |
|
|
||||||
| | | - auto-design functionality |
|
|
||||||
| | | - path request functionality |
|
|
||||||
+---------------+-------------+-----------------------------------------------+
|
|
||||||
|
|
||||||
How to Install
|
How to Install
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
Using prebuilt Docker images
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Our `Docker images <https://hub.docker.com/r/telecominfraproject/oopt-gnpy>`_ contain everything needed to run all examples from this guide.
|
||||||
|
Docker transparently fetches the image over the network upon first use.
|
||||||
|
On Linux and Mac, run:
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: shell-session
|
||||||
|
|
||||||
|
$ docker run -it --rm --volume $(pwd):/shared telecominfraproject/oopt-gnpy
|
||||||
|
root@bea050f186f7:/shared/examples#
|
||||||
|
|
||||||
|
On Windows, launch from Powershell as:
|
||||||
|
|
||||||
|
.. code-block:: powershell
|
||||||
|
|
||||||
|
PS C:\> docker run -it --rm --volume ${PWD}:/shared telecominfraproject/oopt-gnpy
|
||||||
|
root@89784e577d44:/shared/examples#
|
||||||
|
|
||||||
|
In both cases, a directory named ``examples/`` will appear in your current working directory.
|
||||||
|
GNPy automaticallly populates it with example files from the current release.
|
||||||
|
Remove that directory if you want to start from scratch.
|
||||||
|
|
||||||
|
Using Python on your computer
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
**Note**: `gnpy` supports Python 3 only. Python 2 is not supported.
|
**Note**: `gnpy` supports Python 3 only. Python 2 is not supported.
|
||||||
`gnpy` requires Python ≥3.6
|
`gnpy` requires Python ≥3.6
|
||||||
|
|
||||||
@@ -52,10 +77,9 @@ How to Install
|
|||||||
It is recommended that you use a "virtual environment" when installing `gnpy`.
|
It is recommended that you use a "virtual environment" when installing `gnpy`.
|
||||||
Do not install `gnpy` on your system Python.
|
Do not install `gnpy` on your system Python.
|
||||||
|
|
||||||
We recommend the use of the Anaconda Python distribution
|
We recommend the use of the `Anaconda Python distribution <https://www.anaconda.com/download>`_ which comes with many scientific computing
|
||||||
(https://www.anaconda.com/download) which comes with many scientific computing
|
|
||||||
dependencies pre-installed. Anaconda creates a base "virtual environment" for
|
dependencies pre-installed. Anaconda creates a base "virtual environment" for
|
||||||
you automatically. You can also create and manage your conda "virtual
|
you automatically. You can also create and manage your ``conda`` "virtual
|
||||||
environments" yourself (see:
|
environments" yourself (see:
|
||||||
https://conda.io/docs/user-guide/tasks/manage-environments.html)
|
https://conda.io/docs/user-guide/tasks/manage-environments.html)
|
||||||
|
|
||||||
@@ -101,14 +125,13 @@ of the `gnpy` repo and install it with:
|
|||||||
$ python setup.py install # install
|
$ python setup.py install # install
|
||||||
|
|
||||||
To test that `gnpy` was successfully installed, you can run this command. If it
|
To test that `gnpy` was successfully installed, you can run this command. If it
|
||||||
executes without a `ModuleNotFoundError`, you have successfully installed
|
executes without a ``ModuleNotFoundError``, you have successfully installed
|
||||||
`gnpy`.
|
`gnpy`.
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
$ python -c 'import gnpy' # attempt to import gnpy
|
$ python -c 'import gnpy' # attempt to import gnpy
|
||||||
|
|
||||||
$ cd oopt-gnpy
|
|
||||||
$ pytest # run tests
|
$ pytest # run tests
|
||||||
|
|
||||||
Instructions for First Use
|
Instructions for First Use
|
||||||
@@ -120,20 +143,18 @@ It ships with a number of example programs. Release versions will ship with
|
|||||||
fully-functional programs.
|
fully-functional programs.
|
||||||
|
|
||||||
**Note**: *If you are a network operator or involved in route planning and
|
**Note**: *If you are a network operator or involved in route planning and
|
||||||
optimization for your organization, please contact project maintainer James
|
optimization for your organization, please contact project maintainer Jan
|
||||||
Powell <james.powell@telecominfraproject>. gnpy is looking for users with
|
Kundrát <jan.kundrat@telecominfraproject.com>. gnpy is looking for users with
|
||||||
specific, delineated use cases to drive requirements for future
|
specific, delineated use cases to drive requirements for future
|
||||||
development.*
|
development.*
|
||||||
|
|
||||||
**To get started, run the main transmission example:**
|
This example demonstrates how GNPy can be used to check the expected SNR at the end of the line by varying the channel input power:
|
||||||
|
|
||||||
**Note**: *Examples should be run from the examples/ folder.*
|
.. image:: https://telecominfraproject.github.io/oopt-gnpy/docs/images/transmission_main_example.svg
|
||||||
|
:width: 100%
|
||||||
.. code-block:: shell
|
:align: left
|
||||||
$ pwd
|
:alt: Running a simple simulation example
|
||||||
/path/to/oopt-gnpy
|
:target: https://asciinema.org/a/252295
|
||||||
$ cd examples
|
|
||||||
$ python transmission_main_example.py
|
|
||||||
|
|
||||||
By default, this script operates on a single span network defined in
|
By default, this script operates on a single span network defined in
|
||||||
`examples/edfa_example_network.json <examples/edfa_example_network.json>`_
|
`examples/edfa_example_network.json <examples/edfa_example_network.json>`_
|
||||||
@@ -142,10 +163,9 @@ You can specify a different network at the command line as follows. For
|
|||||||
example, to use the CORONET Global network defined in
|
example, to use the CORONET Global network defined in
|
||||||
`examples/CORONET_Global_Topology.json <examples/CORONET_Global_Topology.json>`_:
|
`examples/CORONET_Global_Topology.json <examples/CORONET_Global_Topology.json>`_:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell-session
|
||||||
|
|
||||||
$ cd examples
|
$ ./examples/transmission_main_example.py examples/CORONET_Global_Topology.json
|
||||||
$ python transmission_main_example.py CORONET_Global_Topology.json
|
|
||||||
|
|
||||||
It is also possible to use an Excel file input (for example
|
It is also possible to use an Excel file input (for example
|
||||||
`examples/CORONET_Global_Topology.xls <examples/CORONET_Global_Topology.xls>`_).
|
`examples/CORONET_Global_Topology.xls <examples/CORONET_Global_Topology.xls>`_).
|
||||||
@@ -183,59 +203,59 @@ information to transmit.)
|
|||||||
The EDFA equipment library is a list of supported amplifiers. New amplifiers
|
The EDFA equipment library is a list of supported amplifiers. New amplifiers
|
||||||
can be added and existing ones removed. Three different noise models are available:
|
can be added and existing ones removed. Three different noise models are available:
|
||||||
|
|
||||||
1. `'type_def': 'variable_gain'` is a simplified model simulating a 2-coil EDFA with internal, input and output VOAs. The NF vs gain response is calculated accordingly based on the input parameters: `nf_min`, `nf_max`, and `gain_flatmax`. It is not a simple interpolation but a 2-stage NF calculation.
|
1. ``'type_def': 'variable_gain'`` is a simplified model simulating a 2-coil EDFA with internal, input and output VOAs. The NF vs gain response is calculated accordingly based on the input parameters: ``nf_min``, ``nf_max``, and ``gain_flatmax``. It is not a simple interpolation but a 2-stage NF calculation.
|
||||||
2. `'type_def': 'fixed_gain'` is a fixed gain model. `NF == Cte == nf0` if `gain_min < gain < gain_flatmax`
|
2. ``'type_def': 'fixed_gain'`` is a fixed gain model. `NF == Cte == nf0` if `gain_min < gain < gain_flatmax`
|
||||||
3. `'type_def': None` is an advanced model. A detailed json configuration file is required (by default `examples/std_medium_gain_advanced_config.json <examples/std_medium_gain_advanced_config.json>`_.) It uses a 3rd order polynomial where NF = f(gain), NF_ripple = f(frequency), gain_ripple = f(frequency), N-array dgt = f(frequency). Compared to the previous models, NF ripple and gain ripple are modelled.
|
3. ``'type_def': None`` is an advanced model. A detailed JSON configuration file is required (by default `examples/std_medium_gain_advanced_config.json <examples/std_medium_gain_advanced_config.json>`_). It uses a 3rd order polynomial where NF = f(gain), NF_ripple = f(frequency), gain_ripple = f(frequency), N-array dgt = f(frequency). Compared to the previous models, NF ripple and gain ripple are modelled.
|
||||||
|
|
||||||
For all amplifier models:
|
For all amplifier models:
|
||||||
|
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+------------------------+-----------+-----------------------------------------+
|
||||||
| field | type | description |
|
| field | type | description |
|
||||||
+======================+===========+=========================================+
|
+========================+===========+=========================================+
|
||||||
| `type_variety` | (string) | a unique name to ID the amplifier in the|
|
| ``type_variety`` | (string) | a unique name to ID the amplifier in the|
|
||||||
| | | JSON/Excel template topology input file |
|
| | | JSON/Excel template topology input file |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+------------------------+-----------+-----------------------------------------+
|
||||||
| `out_voa_auto` | (boolean) | auto_design feature to optimize the |
|
| ``out_voa_auto`` | (boolean) | auto_design feature to optimize the |
|
||||||
| | | amplifier output VOA. If true, output |
|
| | | amplifier output VOA. If true, output |
|
||||||
| | | VOA is present and will be used to push |
|
| | | VOA is present and will be used to push |
|
||||||
| | | amplifier gain to its maximum, within |
|
| | | amplifier gain to its maximum, within |
|
||||||
| | | EOL power margins. |
|
| | | EOL power margins. |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+------------------------+-----------+-----------------------------------------+
|
||||||
| `allowed_for_design` | (boolean) | If false, the amplifier will not be |
|
| ``allowed_for_design`` | (boolean) | If false, the amplifier will not be |
|
||||||
| | | picked by auto-design but it can still |
|
| | | picked by auto-design but it can still |
|
||||||
| | | be used as a manual input (from JSON or |
|
| | | be used as a manual input (from JSON or |
|
||||||
| | | Excel template topology files.) |
|
| | | Excel template topology files.) |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+------------------------+-----------+-----------------------------------------+
|
||||||
|
|
||||||
The fiber library currently describes SSMF and NZDF but additional fiber types can be entered by the user following the same model:
|
The fiber library currently describes SSMF and NZDF but additional fiber types can be entered by the user following the same model:
|
||||||
|
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| field | type | description |
|
| field | type | description |
|
||||||
+======================+===========+=========================================+
|
+======================+===========+=========================================+
|
||||||
| `type_variety` | (string) | a unique name to ID the fiber in the |
|
| ``type_variety`` | (string) | a unique name to ID the fiber in the |
|
||||||
| | | JSON or Excel template topology input |
|
| | | JSON or Excel template topology input |
|
||||||
| | | file |
|
| | | file |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `dispersion` | (number) | (s.m-1.m-1) |
|
| ``dispersion`` | (number) | (s.m-1.m-1) |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `gamma` | (number) | 2pi.n2/(lambda*Aeff) (w-2.m-1) |
|
| ``gamma`` | (number) | 2pi.n2/(lambda*Aeff) (w-2.m-1) |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
|
|
||||||
The transceiver equipment library is a list of supported transceivers. New
|
The transceiver equipment library is a list of supported transceivers. New
|
||||||
transceivers can be added and existing ones removed at will by the user. It is
|
transceivers can be added and existing ones removed at will by the user. It is
|
||||||
used to determine the service list path feasibility when running the
|
used to determine the service list path feasibility when running the
|
||||||
path_request_run.py routine.
|
`path_request_run.py routine <examples/path_request_run.py>`_.
|
||||||
|
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| field | type | description |
|
| field | type | description |
|
||||||
+======================+===========+=========================================+
|
+======================+===========+=========================================+
|
||||||
| `type_variety` | (string) | a unique name to ID the transceiver in |
|
| ``type_variety`` | (string) | A unique name to ID the transceiver in |
|
||||||
| | | the JSON or Excel template topology |
|
| | | the JSON or Excel template topology |
|
||||||
| | | input file |
|
| | | input file |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `frequency` | (number) | Min/max as below. |
|
| ``frequency`` | (number) | Min/max as below. |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `mode` | (number) | a list of modes supported by the |
|
| ``mode`` | (number) | A list of modes supported by the |
|
||||||
| | | transponder. New modes can be added at |
|
| | | transponder. New modes can be added at |
|
||||||
| | | will by the user. The modes are specific|
|
| | | will by the user. The modes are specific|
|
||||||
| | | to each transponder type_variety. |
|
| | | to each transponder type_variety. |
|
||||||
@@ -247,61 +267,61 @@ The modes are defined as follows:
|
|||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| field | type | description |
|
| field | type | description |
|
||||||
+======================+===========+=========================================+
|
+======================+===========+=========================================+
|
||||||
| `format` | (string) | a unique name to ID the mode. |
|
| ``format`` | (string) | a unique name to ID the mode |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `baud_rate` | (number) | in Hz |
|
| ``baud_rate`` | (number) | in Hz |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `OSNR` | (number) | min required OSNR in 0.1nm (dB) |
|
| ``OSNR`` | (number) | min required OSNR in 0.1nm (dB) |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `bit_rate` | (number) | in bit/s |
|
| ``bit_rate`` | (number) | in bit/s |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `roll_off` | (number) | Not used. |
|
| ``roll_off`` | (number) | Not used. |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `tx_osnr` | (number) | In dB. OSNR out from transponder. |
|
| ``tx_osnr`` | (number) | In dB. OSNR out from transponder. |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
| `cost` | (number) | Arbitrary unit |
|
| ``cost`` | (number) | Arbitrary unit |
|
||||||
+----------------------+-----------+-----------------------------------------+
|
+----------------------+-----------+-----------------------------------------+
|
||||||
|
|
||||||
Simulation parameters are defined as follows.
|
Simulation parameters are defined as follows.
|
||||||
|
|
||||||
Auto-design automatically creates EDFA amplifier network elements when they are
|
Auto-design automatically creates EDFA amplifier network elements when they are
|
||||||
missing, after a fiber, or between a ROADM and a fiber. This auto-design
|
missing, after a fiber, or between a ROADM and a fiber. This auto-design
|
||||||
functionality can be manually and locally deactivated by introducing a `Fused`
|
functionality can be manually and locally deactivated by introducing a ``Fused``
|
||||||
network element after a `Fiber` or a `Roadm` that doesn't need amplification.
|
network element after a ``Fiber`` or a ``Roadm`` that doesn't need amplification.
|
||||||
The amplifier is chosen in the EDFA list of the equipment library based on
|
The amplifier is chosen in the EDFA list of the equipment library based on
|
||||||
gain, power, and NF criteria. Only the EDFA that are marked
|
gain, power, and NF criteria. Only the EDFA that are marked
|
||||||
`'allowed_for_design': true` are considered.
|
``'allowed_for_design': true`` are considered.
|
||||||
|
|
||||||
For amplifiers defined in the topology JSON input but whose gain = 0
|
For amplifiers defined in the topology JSON input but whose ``gain = 0``
|
||||||
(placeholder), auto-design will set its gain automatically: see `power_mode` in
|
(placeholder), auto-design will set its gain automatically: see ``power_mode`` in
|
||||||
the `Spans` library to find out how the gain is calculated.
|
the ``Spans`` library to find out how the gain is calculated.
|
||||||
|
|
||||||
Span configuration is performed as follows. It is not a list (which may change
|
Span configuration is performed as follows. It is not a list (which may change
|
||||||
in later releases) and the user can only modify the value of existing
|
in later releases) and the user can only modify the value of existing
|
||||||
parameters:
|
parameters:
|
||||||
|
|
||||||
+------------------------+-----------+---------------------------------------------+
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
| field | type | description |
|
| field | type | description |
|
||||||
+========================+===========+=============================================+
|
+=====================================+===========+=============================================+
|
||||||
| `power_mode` | (boolean) | If false, gain mode. Auto-design sets |
|
| ``power_mode`` | (boolean) | If false, gain mode. Auto-design sets |
|
||||||
| | | amplifier gain = preceding span loss, |
|
| | | amplifier gain = preceding span loss, |
|
||||||
| | | unless the amplifier exists and its |
|
| | | unless the amplifier exists and its |
|
||||||
| | | gain > 0 in the topology input json. |
|
| | | gain > 0 in the topology input JSON. |
|
||||||
| | | If true, power mode (recommended for |
|
| | | If true, power mode (recommended for |
|
||||||
| | | auto-design and power sweep.) |
|
| | | auto-design and power sweep.) |
|
||||||
| | | Auto-design sets amplifier power |
|
| | | Auto-design sets amplifier power |
|
||||||
| | | according to delta_power_range. If the |
|
| | | according to delta_power_range. If the |
|
||||||
| | | amplifier exists with gain > 0 in the |
|
| | | amplifier exists with gain > 0 in the |
|
||||||
| | | topology json input, then its gain is |
|
| | | topology JSON input, then its gain is |
|
||||||
| | | translated into a power target/channel. |
|
| | | translated into a power target/channel. |
|
||||||
| | | Moreover, when performing a power sweep |
|
| | | Moreover, when performing a power sweep |
|
||||||
| | | (see power_range_db in the SI |
|
| | | (see ``power_range_db`` in the SI |
|
||||||
| | | configuration library) the power sweep |
|
| | | configuration library) the power sweep |
|
||||||
| | | is performed w/r/t this power target, |
|
| | | is performed w/r/t this power target, |
|
||||||
| | | regardless of preceding amplifiers |
|
| | | regardless of preceding amplifiers |
|
||||||
| | | power saturation/limitations. |
|
| | | power saturation/limitations. |
|
||||||
+------------------------+-----------+---------------------------------------------+
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
| `delta_power_range_db` | (number) | Auto-design only, power-mode |
|
| ``delta_power_range_db`` | (number) | Auto-design only, power-mode |
|
||||||
| | | only. Specifies the [min, max, step] |
|
| | | only. Specifies the [min, max, step] |
|
||||||
| | | power excursion/span. It is a relative |
|
| | | power excursion/span. It is a relative |
|
||||||
| | | power excursion w/r/t the |
|
| | | power excursion w/r/t the |
|
||||||
@@ -334,23 +354,25 @@ parameters:
|
|||||||
| | | power = power_dbm + power_range_db and |
|
| | | power = power_dbm + power_range_db and |
|
||||||
| | | a 23 dB span to |
|
| | | a 23 dB span to |
|
||||||
| | | power = power_dbm + power_range_db + 1 |
|
| | | power = power_dbm + power_range_db + 1 |
|
||||||
+------------------------+-----------+---------------------------------------------+
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
| `max_length` | (number) | Split fiber lengths > max_length. |
|
| ``max_fiber_lineic_loss_for_raman`` | (number) | Maximum linear fiber loss for Raman |
|
||||||
|
| | | amplification use. |
|
||||||
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
|
| ``max_length`` | (number) | Split fiber lengths > max_length. |
|
||||||
| | | Interest to support high level |
|
| | | Interest to support high level |
|
||||||
| | | topologies that do not specify in line |
|
| | | topologies that do not specify in line |
|
||||||
| | | amplification sites. For example the |
|
| | | amplification sites. For example the |
|
||||||
| | | CORONET_Global_Topology.xls defines |
|
| | | CORONET_Global_Topology.xls defines |
|
||||||
| | | links > 1000km between 2 sites: it |
|
| | | links > 1000km between 2 sites: it |
|
||||||
| | | couldn't be simulated if these links |
|
| | | couldn't be simulated if these links |
|
||||||
| | | were not splitted in shorter span |
|
| | | were not split in shorter span lengths. |
|
||||||
| | | lengths. |
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
+------------------------+-----------+---------------------------------------------+
|
| ``length_unit`` | "m"/"km" | Unit for ``max_length``. |
|
||||||
| `length_unit` | "m"/"km" | Unit for max_length. |
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
+------------------------+-----------+---------------------------------------------+
|
| ``max_loss`` | (number) | Not used in the current code |
|
||||||
| `max_loss` | (number) | Not used in the current code |
|
|
||||||
| | | implementation. |
|
| | | implementation. |
|
||||||
+------------------------+-----------+---------------------------------------------+
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
| `padding` | (number) | In dB. Min span loss before putting an |
|
| ``padding`` | (number) | In dB. Min span loss before putting an |
|
||||||
| | | attenuator before fiber. Attenuator |
|
| | | attenuator before fiber. Attenuator |
|
||||||
| | | value |
|
| | | value |
|
||||||
| | | Fiber.att_in = max(0, padding - span_loss). |
|
| | | Fiber.att_in = max(0, padding - span_loss). |
|
||||||
@@ -364,25 +386,23 @@ parameters:
|
|||||||
| | | completed to have span_loss = padding. |
|
| | | completed to have span_loss = padding. |
|
||||||
| | | Therefore it is not possible to set |
|
| | | Therefore it is not possible to set |
|
||||||
| | | span_loss < padding. |
|
| | | span_loss < padding. |
|
||||||
+------------------------+-----------+---------------------------------------------+
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
| `EOL` | (number) | All fiber span loss ageing. The value |
|
| ``EOL`` | (number) | All fiber span loss ageing. The value |
|
||||||
| | | is added to the con_out (fiber output |
|
| | | is added to the con_out (fiber output |
|
||||||
| | | connector). So the design and the path |
|
| | | connector). So the design and the path |
|
||||||
| | | feasibility are performed with |
|
| | | feasibility are performed with |
|
||||||
| | | span_loss + EOL. EOL cannot be set |
|
| | | span_loss + EOL. EOL cannot be set |
|
||||||
| | | manually for a given fiber span |
|
| | | manually for a given fiber span |
|
||||||
| | | (workaround is to specify higher con_out |
|
| | | (workaround is to specify higher |
|
||||||
| | | loss for this fiber). |
|
| | | ``con_out`` loss for this fiber). |
|
||||||
+------------------------+-----------+---------------------------------------------+
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
| `con_in`, `con_out` | (number) | Default values if Fiber/params/con_in/out |
|
| ``con_in``, | (number) | Default values if Fiber/params/con_in/out |
|
||||||
| | | is None in the topology input |
|
| ``con_out`` | | is None in the topology input |
|
||||||
| | | description. This default value is |
|
| | | description. This default value is |
|
||||||
| | | ignored if a Fiber/params/con_in/out |
|
| | | ignored if a Fiber/params/con_in/out |
|
||||||
| | | value is input in the topology for a |
|
| | | value is input in the topology for a |
|
||||||
| | | given Fiber. |
|
| | | given Fiber. |
|
||||||
+------------------------+-----------+---------------------------------------------+
|
+-------------------------------------+-----------+---------------------------------------------+
|
||||||
|
|
||||||
**[1]**
|
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@@ -405,33 +425,36 @@ parameters:
|
|||||||
ROADMs can be configured as follows. The user can only modify the value of
|
ROADMs can be configured as follows. The user can only modify the value of
|
||||||
existing parameters:
|
existing parameters:
|
||||||
|
|
||||||
+-------------------------+-----------+---------------------------------------------+
|
+--------------------------+-----------+---------------------------------------------+
|
||||||
| field | type | description |
|
| field | type | description |
|
||||||
+=========================+===========+=============================================+
|
+==========================+===========+=============================================+
|
||||||
|`gain_mode_default_loss` | (number) | Default value if Roadm/params/loss is |
|
| ``target_pch_out_db`` | (number) | Auto-design sets the ROADM egress channel |
|
||||||
| | | None in the topology input description. |
|
| | | power. This reflects typical control loop |
|
||||||
|
| | | algorithms that adjust ROADM losses to |
|
||||||
|
| | | equalize channels (eg coming from different |
|
||||||
|
| | | ingress direction or add ports) |
|
||||||
|
| | | This is the default value |
|
||||||
|
| | | Roadm/params/target_pch_out_db if no value |
|
||||||
|
| | | is given in the ``Roadm`` element in the |
|
||||||
|
| | | topology input description. |
|
||||||
| | | This default value is ignored if a |
|
| | | This default value is ignored if a |
|
||||||
| | | params/loss value is input in the |
|
| | | params/target_pch_out_db value is input in |
|
||||||
| | | topology for a given ROADM. |
|
| | | the topology for a given ROADM. |
|
||||||
+-------------------------+-----------+---------------------------------------------+
|
+--------------------------+-----------+---------------------------------------------+
|
||||||
|`power_mode_pref` | (number) | Power mode only. Auto-design sets the |
|
| ``add_drop_osnr`` | (number) | OSNR contribution from the add/drop ports |
|
||||||
| | | power of ROADM ingress amplifiers to |
|
+--------------------------+-----------+---------------------------------------------+
|
||||||
| | | power_dbm + power_range_db, |
|
| ``restrictions`` | (dict of | If non-empty, keys ``preamp_variety_list`` |
|
||||||
| | | regardless of existing gain settings |
|
| | strings) | and ``booster_variety_list`` represent |
|
||||||
| | | from the topology JSON input. |
|
| | | list of ``type_variety`` amplifiers which |
|
||||||
| | | Auto-design sets the Roadm loss so that |
|
| | | are allowed for auto-design within ROADM's |
|
||||||
| | | its egress channel power = power_mode_pref, |
|
| | | line degrees. |
|
||||||
| | | regardless of existing loss settings |
|
| | | |
|
||||||
| | | from the topology JSON input. It means |
|
| | | If no booster should be placed on a degree, |
|
||||||
| | | that the output power from a ROADM (and |
|
| | | insert a ``Fused`` node on the degree |
|
||||||
| | | therefore its OSNR contribution) is Cte |
|
| | | output. |
|
||||||
| | | and not depending from power_dbm and |
|
+--------------------------+-----------+---------------------------------------------+
|
||||||
| | | power_range_db sweep settings. This |
|
|
||||||
| | | choice is meant to reflect some typical |
|
|
||||||
| | | control loop algorithms. |
|
|
||||||
+-------------------------+-----------+---------------------------------------------+
|
|
||||||
|
|
||||||
The `SpectralInformation` object can be configured as follows. The user can
|
The ``SpectralInformation`` object can be configured as follows. The user can
|
||||||
only modify the value of existing parameters. It defines a spectrum of N
|
only modify the value of existing parameters. It defines a spectrum of N
|
||||||
identical carriers. While the code libraries allow for different carriers and
|
identical carriers. While the code libraries allow for different carriers and
|
||||||
power levels, the current user parametrization only allows one carrier type and
|
power levels, the current user parametrization only allows one carrier type and
|
||||||
@@ -440,21 +463,18 @@ one power/channel definition.
|
|||||||
+----------------------+-----------+-------------------------------------------+
|
+----------------------+-----------+-------------------------------------------+
|
||||||
| field | type | description |
|
| field | type | description |
|
||||||
+======================+===========+===========================================+
|
+======================+===========+===========================================+
|
||||||
| `f_min/max` | (number) | In Hz. Carrier min max excursion |
|
| ``f_min``, | (number) | In Hz. Carrier min max excursion. |
|
||||||
|
| ``f_max`` | | |
|
||||||
+----------------------+-----------+-------------------------------------------+
|
+----------------------+-----------+-------------------------------------------+
|
||||||
| `baud_rate` | (number) | In Hz. Simulated baud rate. |
|
| ``baud_rate`` | (number) | In Hz. Simulated baud rate. |
|
||||||
+----------------------+-----------+-------------------------------------------+
|
+----------------------+-----------+-------------------------------------------+
|
||||||
| `spacing` | (number) | In Hz. Carrier spacing. |
|
| ``spacing`` | (number) | In Hz. Carrier spacing. |
|
||||||
+----------------------+-----------+-------------------------------------------+
|
+----------------------+-----------+-------------------------------------------+
|
||||||
| `roll_off` | (number) | Not used. |
|
| ``roll_off`` | (number) | Not used. |
|
||||||
+----------------------+-----------+-------------------------------------------+
|
+----------------------+-----------+-------------------------------------------+
|
||||||
| `OSNR` | (number) | Not used. |
|
| ``tx_osnr`` | (number) | In dB. OSNR out from transponder. |
|
||||||
+----------------------+-----------+-------------------------------------------+
|
+----------------------+-----------+-------------------------------------------+
|
||||||
| `bit_rate` | (number) | Not used. |
|
| ``power_dbm`` | (number) | Reference channel power. In gain mode |
|
||||||
+----------------------+-----------+-------------------------------------------+
|
|
||||||
| `tx_osnr` | (number) | In dB. OSNR out from transponder. |
|
|
||||||
+----------------------+-----------+-------------------------------------------+
|
|
||||||
| `power_dbm` | (number) | Reference channel power. In gain mode |
|
|
||||||
| | | (see spans/power_mode = false), all gain |
|
| | | (see spans/power_mode = false), all gain |
|
||||||
| | | settings are offset w/r/t this reference |
|
| | | settings are offset w/r/t this reference |
|
||||||
| | | power. In power mode, it is the |
|
| | | power. In power mode, it is the |
|
||||||
@@ -467,17 +487,30 @@ one power/channel definition.
|
|||||||
| | | power sweep is defined (see after) the |
|
| | | power sweep is defined (see after) the |
|
||||||
| | | design is not repeated. |
|
| | | design is not repeated. |
|
||||||
+----------------------+-----------+-------------------------------------------+
|
+----------------------+-----------+-------------------------------------------+
|
||||||
| `power_range_db` | (number) | Power sweep excursion around power_dbm. |
|
| ``power_range_db`` | (number) | Power sweep excursion around power_dbm. |
|
||||||
| | | It is not the min and max channel power |
|
| | | It is not the min and max channel power |
|
||||||
| | | values! The reference power becomes: |
|
| | | values! The reference power becomes: |
|
||||||
| | | power_range_db + power_dbm. |
|
| | | power_range_db + power_dbm. |
|
||||||
+----------------------+-----------+-------------------------------------------+
|
+----------------------+-----------+-------------------------------------------+
|
||||||
|
| ``sys_margins`` | (number) | In dB. Added margin on min required |
|
||||||
|
| | | transceiver OSNR. |
|
||||||
|
+----------------------+-----------+-------------------------------------------+
|
||||||
|
|
||||||
The `transmission_main_example.py <examples/transmission_main_example.py>`_
|
The `transmission_main_example.py <examples/transmission_main_example.py>`_ script propagates a spectrum of channels at 32 Gbaud, 50 GHz spacing and 0 dBm/channel.
|
||||||
script propagates a spectrum of channels at 32 Gbaud, 50 GHz spacing and 0
|
Launch power can be overridden by using the ``--power`` argument.
|
||||||
dBm/channel. These are not yet parametrized but can be modified directly in the
|
Spectrum information is not yet parametrized but can be modified directly in the ``eqpt_config.json`` (via the ``SpectralInformation`` -SI- structure) to accommodate any baud rate or spacing.
|
||||||
script (via the SpectralInformation structure) to accommodate any baud rate,
|
The number of channel is computed based on ``spacing`` and ``f_min``, ``f_max`` values.
|
||||||
spacing, power or channel count demand.
|
|
||||||
|
An experimental support for Raman amplification is available:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ ./examples/transmission_main_example.py \
|
||||||
|
examples/raman_edfa_example_network.json \
|
||||||
|
--sim examples/sim_params.json --show-channels
|
||||||
|
|
||||||
|
Configuration of Raman pumps (their frequencies, power and pumping direction) is done via the `RamanFiber element in the network topology <examples/raman_edfa_example_network.json>`_.
|
||||||
|
General numeric parameters for simulaiton control are provided in the `examples/sim_params.json <examples/sim_params.json>`_.
|
||||||
|
|
||||||
Use `examples/path_requests_run.py <examples/path_requests_run.py>`_ to run multiple optimizations as follows:
|
Use `examples/path_requests_run.py <examples/path_requests_run.py>`_ to run multiple optimizations as follows:
|
||||||
|
|
||||||
@@ -486,7 +519,7 @@ Use `examples/path_requests_run.py <examples/path_requests_run.py>`_ to run mult
|
|||||||
$ python path_requests_run.py -h
|
$ python path_requests_run.py -h
|
||||||
Usage: path_requests_run.py [-h] [-v] [-o OUTPUT] [network_filename] [service_filename] [eqpt_filename]
|
Usage: path_requests_run.py [-h] [-v] [-o OUTPUT] [network_filename] [service_filename] [eqpt_filename]
|
||||||
|
|
||||||
The `network_filename` and `service_filename` can be an XLS or JSON file. The `eqpt_filename` must be a JSON file.
|
The ``network_filename`` and ``service_filename`` can be an XLS or JSON file. The ``eqpt_filename`` must be a JSON file.
|
||||||
|
|
||||||
To see an example of it, run:
|
To see an example of it, run:
|
||||||
|
|
||||||
@@ -497,10 +530,10 @@ To see an example of it, run:
|
|||||||
|
|
||||||
This program requires a list of connections to be estimated and the equipment
|
This program requires a list of connections to be estimated and the equipment
|
||||||
library. The program computes performances for the list of services (accepts
|
library. The program computes performances for the list of services (accepts
|
||||||
json or excel format) using the same spectrum propagation modules as
|
JSON or Excel format) using the same spectrum propagation modules as
|
||||||
transmission_main_example.py. Explanation on the Excel template is provided in
|
``transmission_main_example.py``. Explanation on the Excel template is provided in
|
||||||
the `Excel_userguide.rst <Excel_userguide.rst#service-sheet>`_. Template for
|
the `Excel_userguide.rst <Excel_userguide.rst#service-sheet>`_. Template for
|
||||||
the json format can be found here: `service-template.json
|
the JSON format can be found here: `service-template.json
|
||||||
<service-template.json>`_.
|
<service-template.json>`_.
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
@@ -509,8 +542,8 @@ Contributing
|
|||||||
``gnpy`` is looking for additional contributors, especially those with experience
|
``gnpy`` is looking for additional contributors, especially those with experience
|
||||||
planning and maintaining large-scale, real-world mesh optical networks.
|
planning and maintaining large-scale, real-world mesh optical networks.
|
||||||
|
|
||||||
To get involved, please contact James Powell
|
To get involved, please contact Jan Kundrát
|
||||||
<james.powell@telecominfraproject.com> or Gert Grammel <ggrammel@juniper.net>.
|
<jan.kundrat@telecominfraproject.com> or Gert Grammel <ggrammel@juniper.net>.
|
||||||
|
|
||||||
``gnpy`` contributions are currently limited to members of `TIP
|
``gnpy`` contributions are currently limited to members of `TIP
|
||||||
<http://telecominfraproject.com>`_. Membership is free and open to all.
|
<http://telecominfraproject.com>`_. Membership is free and open to all.
|
||||||
@@ -568,6 +601,11 @@ implementations.
|
|||||||
:alt: Build Status
|
:alt: Build Status
|
||||||
:scale: 100%
|
:scale: 100%
|
||||||
|
|
||||||
|
.. |doi| image:: https://zenodo.org/badge/96894149.svg
|
||||||
|
:target: https://zenodo.org/badge/latestdoi/96894149
|
||||||
|
:alt: DOI
|
||||||
|
:scale: 100%
|
||||||
|
|
||||||
TIP OOPT/PSE & PSE WG Charter
|
TIP OOPT/PSE & PSE WG Charter
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -874,7 +874,7 @@ month={Sept},}
|
|||||||
number = {7},
|
number = {7},
|
||||||
journal = {Optics Express},
|
journal = {Optics Express},
|
||||||
urlyear = {2017-11-14},
|
urlyear = {2017-11-14},
|
||||||
year = {2012-03-26},
|
date = {2012-03-26},
|
||||||
year = {2012},
|
year = {2012},
|
||||||
pages = {7777},
|
pages = {7777},
|
||||||
author = {Bononi, A. and Serena, P. and Rossi, N. and Grellier, E. and Vacondio, F.}
|
author = {Bononi, A. and Serena, P. and Rossi, N. and Grellier, E. and Vacondio, F.}
|
||||||
@@ -1114,7 +1114,7 @@ month={Sept},}
|
|||||||
number = {26},
|
number = {26},
|
||||||
journal = {Optics Express},
|
journal = {Optics Express},
|
||||||
urlyear = {2017-11-16},
|
urlyear = {2017-11-16},
|
||||||
year = {2013-12-30},
|
date = {2013-12-30},
|
||||||
year = {2013},
|
year = {2013},
|
||||||
pages = {32254},
|
pages = {32254},
|
||||||
author = {Bononi, Alberto and Beucher, Ottmar and Serena, Paolo}
|
author = {Bononi, Alberto and Beucher, Ottmar and Serena, Paolo}
|
||||||
|
|||||||
@@ -173,5 +173,4 @@ texinfo_documents = [
|
|||||||
'Miscellaneous'),
|
'Miscellaneous'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
autodoc_default_flags = ['members', 'undoc-members', 'private-members', 'show-inheritance']
|
||||||
|
|
||||||
|
|||||||
BIN
docs/images/GNPy-banner.png
Normal file
BIN
docs/images/GNPy-banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 518 KiB |
@@ -51,6 +51,8 @@ Contributors in alphabetical order
|
|||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| David | Boertjes | Ciena | dboertje@ciena.com |
|
| David | Boertjes | Ciena | dboertje@ciena.com |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
|
| Diego | Landa | Facebook | dlanda@fb.com |
|
||||||
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| Esther | Le Rouzic | Orange | esther.lerouzic@orange.com |
|
| Esther | Le Rouzic | Orange | esther.lerouzic@orange.com |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| Gabriele | Galimberti | Cisco | ggalimbe@cisco.com |
|
| Gabriele | Galimberti | Cisco | ggalimbe@cisco.com |
|
||||||
@@ -61,20 +63,28 @@ Contributors in alphabetical order
|
|||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| James | Powell | Telecom Infra Project | james.powell@telecominfraproject.com |
|
| James | Powell | Telecom Infra Project | james.powell@telecominfraproject.com |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| Jeanluc | Auge | Orange | jeanluc.auge@orange.com |
|
| Jan | Kundrát | Telecom Infra Project | jan.kundrat@telecominfraproject.com |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| Jonas | Martensson | RISE Research Sweden | jonas.martensson@ri.se |
|
| Jeanluc | Augé | Orange | jeanluc.auge@orange.com |
|
||||||
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
|
| Jonas | Mårtensson | RISE Research Sweden | jonas.martensson@ri.se |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| Mattia | Cantono | Politecnico di Torino | mattia.cantono@polito.it |
|
| Mattia | Cantono | Politecnico di Torino | mattia.cantono@polito.it |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| Miguel | Garrich | University Catalunya | miquel.garrich@upct.es |
|
| Miguel | Garrich | University Catalunya | miquel.garrich@upct.es |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| Stefan | Melin | Telia Company | Stefan.Melin@teliacompany.com |
|
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
|
||||||
| Raj | Nagarajan | Lumentum | raj.nagarajan@lumentum.com |
|
| Raj | Nagarajan | Lumentum | raj.nagarajan@lumentum.com |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
|
| Roberts | Miculens | Lattelecom | roberts.miculens@lattelecom.lv |
|
||||||
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
|
| Shengxiang | Zhu | University of Arizona | szhu@email.arizona.edu |
|
||||||
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
|
| Stefan | Melin | Telia Company | Stefan.Melin@teliacompany.com |
|
||||||
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
| Vittorio | Curri | Politecnico di Torino | vittorio.curri@polito.it |
|
| Vittorio | Curri | Politecnico di Torino | vittorio.curri@polito.it |
|
||||||
+----------+------------+-----------------------+--------------------------------------+
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
|
| Xufeng | Liu | Jabil | xufeng_liu@jabil.com |
|
||||||
|
+----------+------------+-----------------------+--------------------------------------+
|
||||||
|
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,39 @@ gnpy\.core package
|
|||||||
Submodules
|
Submodules
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
gnpy\.core\.ansi_escapes module
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: gnpy.core.ansi_escapes
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
gnpy\.core\.convert module
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: gnpy.core.convert
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
gnpy\.core\.elements module
|
gnpy\.core\.elements module
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
.. automodule:: gnpy.core.elements
|
.. automodule:: gnpy.core.elements
|
||||||
|
|
||||||
|
gnpy\.core\.equipment module
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: gnpy.core.equipment
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
gnpy\.core\.exceptions module
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: gnpy.core.exceptions
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
@@ -16,30 +45,34 @@ gnpy\.core\.execute module
|
|||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
.. automodule:: gnpy.core.execute
|
.. automodule:: gnpy.core.execute
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
gnpy\.core\.info module
|
gnpy\.core\.info module
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
.. automodule:: gnpy.core.info
|
.. automodule:: gnpy.core.info
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
gnpy\.core\.network module
|
gnpy\.core\.network module
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
.. automodule:: gnpy.core.network
|
.. automodule:: gnpy.core.network
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
gnpy\.core\.node module
|
gnpy\.core\.node module
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
.. automodule:: gnpy.core.node
|
.. automodule:: gnpy.core.node
|
||||||
|
|
||||||
|
gnpy\.core\.request module
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: gnpy.core.request
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
gnpy\.core\.service_sheet module
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. automodule:: gnpy.core.service_sheet
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
@@ -48,23 +81,14 @@ gnpy\.core\.units module
|
|||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
.. automodule:: gnpy.core.units
|
.. automodule:: gnpy.core.units
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
gnpy\.core\.utils module
|
gnpy\.core\.utils module
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
.. automodule:: gnpy.core.utils
|
.. automodule:: gnpy.core.utils
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
Module contents
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
.. automodule:: gnpy.core
|
.. automodule:: gnpy.core
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|||||||
@@ -12,6 +12,3 @@ Module contents
|
|||||||
---------------
|
---------------
|
||||||
|
|
||||||
.. automodule:: gnpy
|
.. automodule:: gnpy
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|||||||
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)
|
||||||
7631
examples/CORONET_CONUS_Topology.json
Normal file
7631
examples/CORONET_CONUS_Topology.json
Normal file
File diff suppressed because it is too large
Load Diff
160
examples/Juniper-BoosterHG.json
Normal file
160
examples/Juniper-BoosterHG.json
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
{
|
||||||
|
"nf_fit_coeff": [
|
||||||
|
0.0008,
|
||||||
|
0.0272,
|
||||||
|
-0.2249,
|
||||||
|
6.4902
|
||||||
|
],
|
||||||
|
"f_min": 191.35e12,
|
||||||
|
"f_max": 196.1e12,
|
||||||
|
"nf_ripple": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"gain_ripple": [
|
||||||
|
0.15017064489112,
|
||||||
|
0.14157768006701,
|
||||||
|
0.00223094639866,
|
||||||
|
-0.06701528475711,
|
||||||
|
-0.05982935510889,
|
||||||
|
-0.01028161641541,
|
||||||
|
0.02740682579566,
|
||||||
|
0.02795958961474,
|
||||||
|
0.00107516750419,
|
||||||
|
-0.02199015912898,
|
||||||
|
-0.00877407872698,
|
||||||
|
0.0453465242881,
|
||||||
|
0.1204721524288,
|
||||||
|
0.18936662479061,
|
||||||
|
0.23826109715241,
|
||||||
|
0.26956762981574,
|
||||||
|
0.27836159966498,
|
||||||
|
0.26941687604691,
|
||||||
|
0.23579878559464,
|
||||||
|
0.18147717755444,
|
||||||
|
0.1191656197655,
|
||||||
|
0.05921587102177,
|
||||||
|
0.01509526800668,
|
||||||
|
-0.01053287269681,
|
||||||
|
-0.02475397822447,
|
||||||
|
-0.01847257118928,
|
||||||
|
-0.00420121440538,
|
||||||
|
0.01584903685091,
|
||||||
|
0.0399193886097,
|
||||||
|
0.04494451423784,
|
||||||
|
0.04961788107202,
|
||||||
|
0.03378873534338,
|
||||||
|
0.01027114740367,
|
||||||
|
-0.01319618927973,
|
||||||
|
-0.04962835008375,
|
||||||
|
-0.0765630234506,
|
||||||
|
-0.10606051088777,
|
||||||
|
-0.13550774706866,
|
||||||
|
-0.15460322445561,
|
||||||
|
-0.17113588777219,
|
||||||
|
-0.18053287269681,
|
||||||
|
-0.18324644053602,
|
||||||
|
-0.19440221943049,
|
||||||
|
-0.20897508375209,
|
||||||
|
-0.23575900335007,
|
||||||
|
-0.25188965661642,
|
||||||
|
-0.22244242043552,
|
||||||
|
-0.15656302345061
|
||||||
|
],
|
||||||
|
"dgt": [
|
||||||
|
2.4553191172498,
|
||||||
|
2.44342862248888,
|
||||||
|
2.41879254989742,
|
||||||
|
2.38192717604575,
|
||||||
|
2.33147727493671,
|
||||||
|
2.26678136721453,
|
||||||
|
2.19013043016015,
|
||||||
|
2.10336369905543,
|
||||||
|
2.01414465424155,
|
||||||
|
1.92915262384742,
|
||||||
|
1.85543800978691,
|
||||||
|
1.79748596476494,
|
||||||
|
1.75428006928365,
|
||||||
|
1.72461030013125,
|
||||||
|
1.70379790088896,
|
||||||
|
1.68845480656382,
|
||||||
|
1.6761448370895,
|
||||||
|
1.66286684904577,
|
||||||
|
1.64799163036252,
|
||||||
|
1.63068023161292,
|
||||||
|
1.61073904908309,
|
||||||
|
1.58973304612691,
|
||||||
|
1.56750088631614,
|
||||||
|
1.54578500307573,
|
||||||
|
1.5242627235492,
|
||||||
|
1.50335352244996,
|
||||||
|
1.48420288841848,
|
||||||
|
1.46637521309853,
|
||||||
|
1.44977369463316,
|
||||||
|
1.43476940680732,
|
||||||
|
1.42089447397912,
|
||||||
|
1.40864903907609,
|
||||||
|
1.3966294751726,
|
||||||
|
1.38430337205545,
|
||||||
|
1.3710092503689,
|
||||||
|
1.35690844654118,
|
||||||
|
1.3405812000038,
|
||||||
|
1.32210817897091,
|
||||||
|
1.30069883494415,
|
||||||
|
1.27657903892303,
|
||||||
|
1.24931318255134,
|
||||||
|
1.21911100318577,
|
||||||
|
1.18632744096844,
|
||||||
|
1.15209185089701,
|
||||||
|
1.11575888725852,
|
||||||
|
1.07773189112355,
|
||||||
|
1.03941448941778,
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -11,64 +11,72 @@ If not present in the "Nodes" sheet, the "Type" column will be implicitly
|
|||||||
determined based on the topology.
|
determined based on the topology.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sys import exit
|
|
||||||
try:
|
try:
|
||||||
from xlrd import open_workbook
|
from xlrd import open_workbook
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
exit('Required: `pip install xlrd`')
|
exit('Required: `pip install xlrd`')
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from collections import namedtuple, defaultdict
|
|
||||||
|
|
||||||
|
PARSER = ArgumentParser()
|
||||||
Shortlink = namedtuple('Link', 'src dest')
|
PARSER.add_argument('workbook', nargs='?', default='meshTopologyExampleV2.xls',
|
||||||
|
|
||||||
Shortnode = namedtuple('Node', 'nodename eqt')
|
|
||||||
|
|
||||||
parser = ArgumentParser()
|
|
||||||
parser.add_argument('workbook', nargs='?', default='meshTopologyExampleV2.xls',
|
|
||||||
help='create the mandatory columns in Eqpt sheet')
|
help='create the mandatory columns in Eqpt sheet')
|
||||||
all_rows = lambda sh, start=0: (sh.row(x) for x in range(start, sh.nrows))
|
ALL_ROWS = lambda sh, start=0: (sh.row(x) for x in range(start, sh.nrows))
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
""" Node element contains uid, list of connected nodes and eqpt type
|
||||||
|
"""
|
||||||
|
def __init__(self, uid, to_node):
|
||||||
|
self.uid = uid
|
||||||
|
self.to_node = to_node
|
||||||
|
self.eqpt = None
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'uid {self.uid} \nto_node {[node for node in self.to_node]}\neqpt {self.eqpt}\n'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'uid {self.uid} \nto_node {[node for node in self.to_node]}\neqpt {self.eqpt}\n'
|
||||||
|
|
||||||
def read_excel(input_filename):
|
def read_excel(input_filename):
|
||||||
with open_workbook(input_filename) as wb:
|
""" read excel Nodes and Links sheets and create a dict of nodes with
|
||||||
|
their to_nodes and type of eqpt
|
||||||
|
"""
|
||||||
|
with open_workbook(input_filename) as wobo:
|
||||||
# reading Links sheet
|
# reading Links sheet
|
||||||
links_sheet = wb.sheet_by_name('Links')
|
links_sheet = wobo.sheet_by_name('Links')
|
||||||
links = []
|
nodes = {}
|
||||||
nodeoccuranceinlinks = []
|
for row in ALL_ROWS(links_sheet, start=5):
|
||||||
links_by_src = defaultdict(list)
|
try:
|
||||||
links_by_dest = defaultdict(list)
|
nodes[row[0].value].to_node.append(row[1].value)
|
||||||
for row in all_rows(links_sheet, start=5):
|
except KeyError:
|
||||||
links.append(Shortlink(row[0].value,row[1].value))
|
nodes[row[0].value] = Node(row[0].value, [row[1].value])
|
||||||
links_by_src[row[0].value].append(Shortnode(row[1].value,''))
|
try:
|
||||||
links_by_dest[row[1].value].append(Shortnode(row[0].value,''))
|
nodes[row[1].value].to_node.append(row[0].value)
|
||||||
#print(f'source {links[len(links)-1].src} dest {links[len(links)-1].dest}')
|
except KeyError:
|
||||||
nodeoccuranceinlinks.append(row[0].value)
|
nodes[row[1].value] = Node(row[1].value, [row[0].value])
|
||||||
nodeoccuranceinlinks.append(row[1].value)
|
|
||||||
|
|
||||||
# reading Nodes sheet
|
nodes_sheet = wobo.sheet_by_name('Nodes')
|
||||||
nodes_sheet = wb.sheet_by_name('Nodes')
|
for row in ALL_ROWS(nodes_sheet, start=5):
|
||||||
nodes = []
|
node = row[0].value
|
||||||
node_degree = []
|
eqpt = row[6].value
|
||||||
for row in all_rows(nodes_sheet, start=5) :
|
try:
|
||||||
|
if eqpt == 'ILA' and len(nodes[node].to_node) != 2:
|
||||||
|
print(f'Inconsistancy ILA node with degree > 2: {node} ')
|
||||||
|
exit()
|
||||||
|
if eqpt == '' and len(nodes[node].to_node) == 2:
|
||||||
|
nodes[node].eqpt = 'ILA'
|
||||||
|
elif eqpt == '' and len(nodes[node].to_node) != 2:
|
||||||
|
nodes[node].eqpt = 'ROADM'
|
||||||
|
else:
|
||||||
|
nodes[node].eqpt = eqpt
|
||||||
|
except KeyError:
|
||||||
|
print(f'inconsistancy between nodes and links sheet: {node} is not listed in links')
|
||||||
|
exit()
|
||||||
|
return nodes
|
||||||
|
|
||||||
temp_eqt = row[6].value
|
def create_eqt_template(nodes, input_filename):
|
||||||
# verify node degree to confirm eqt type
|
""" writes list of node A node Z corresponding to Nodes and Links sheets in order
|
||||||
node_degree.append(nodeoccuranceinlinks.count(row[0].value))
|
to help user populating Eqpt
|
||||||
if temp_eqt.lower() == 'ila' and nodeoccuranceinlinks.count(row[0].value) !=2 :
|
"""
|
||||||
print(f'Inconsistancy: node {nodes[len(nodes)-1]} has degree \
|
|
||||||
{node_degree[len(nodes)-1]} and can not be an ILA ... replaced by ROADM')
|
|
||||||
temp_eqt = 'ROADM'
|
|
||||||
if temp_eqt == '' and nodeoccuranceinlinks.count(row[0].value) == 2 :
|
|
||||||
temp_eqt = 'ILA'
|
|
||||||
if temp_eqt == '' and nodeoccuranceinlinks.count(row[0].value) != 2 :
|
|
||||||
temp_eqt = 'ROADM'
|
|
||||||
# print(f'node {nodes[len(nodes)-1]} eqt {temp_eqt}')
|
|
||||||
nodes.append(Shortnode(row[0].value,temp_eqt))
|
|
||||||
# print(len(nodes)-1)
|
|
||||||
print(f'reading: node {nodes[len(nodes)-1].nodename} eqpt {temp_eqt}')
|
|
||||||
return links,nodes, links_by_src , links_by_dest
|
|
||||||
|
|
||||||
def create_eqt_template(links,nodes, links_by_src , links_by_dest, input_filename):
|
|
||||||
output_filename = f'{input_filename[:-4]}_eqpt_sheet.txt'
|
output_filename = f'{input_filename[:-4]}_eqpt_sheet.txt'
|
||||||
with open(output_filename, 'w', encoding='utf-8') as my_file:
|
with open(output_filename, 'w', encoding='utf-8') as my_file:
|
||||||
# print header similar to excel
|
# print header similar to excel
|
||||||
@@ -77,27 +85,17 @@ def create_eqt_template(links,nodes, links_by_src , links_by_dest, input_filenam
|
|||||||
\nNode A \tNode Z \tamp type \tatt_in \tamp gain \ttilt \tatt_out\
|
\nNode A \tNode Z \tamp type \tatt_in \tamp gain \ttilt \tatt_out\
|
||||||
amp type \tatt_in \tamp gain \ttilt \tatt_out\n')
|
amp type \tatt_in \tamp gain \ttilt \tatt_out\n')
|
||||||
|
|
||||||
tab = []
|
|
||||||
temp = []
|
for node in nodes.values():
|
||||||
i = 0
|
if node.eqpt == 'ILA':
|
||||||
for lk in links:
|
my_file.write(f'{node.uid}\t{node.to_node[0]}\n')
|
||||||
if [e for n,e in nodes if n==lk.src][0] != 'FUSED' :
|
if node.eqpt == 'ROADM':
|
||||||
temp = [lk.src , lk.dest]
|
for to_node in node.to_node:
|
||||||
tab.append(temp)
|
my_file.write(f'{node.uid}\t{to_node}\n')
|
||||||
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] :
|
|
||||||
temp = [n.nodename , src.nodename]
|
|
||||||
tab.append(temp)
|
|
||||||
# print(temp)
|
|
||||||
my_file.write(f'{temp[0]}\t{temp[1]}\n')
|
|
||||||
i = i + 1
|
|
||||||
print(f'File {output_filename} successfully created with Node A - Node Z ' +
|
print(f'File {output_filename} successfully created with Node A - Node Z ' +
|
||||||
' entries for Eqpt sheet in excel file.')
|
' entries for Eqpt sheet in excel file.')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
args = parser.parse_args()
|
ARGS = PARSER.parse_args()
|
||||||
input_filename = args.workbook
|
create_eqt_template(read_excel(ARGS.workbook), ARGS.workbook)
|
||||||
links,nodes,links_by_src, links_by_dest = read_excel(input_filename)
|
|
||||||
create_eqt_template(links,nodes, links_by_src , links_by_dest , input_filename)
|
|
||||||
|
|||||||
1033
examples/demo.json
Normal file
1033
examples/demo.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"nf_ripple": "NFR0_96.txt",
|
"nf_ripple": "NFR_96.txt",
|
||||||
"gain_ripple": "DFG0_96.txt",
|
"gain_ripple": "DFG_96.txt",
|
||||||
"dgt": "DGT_96.txt"
|
"dgt": "DGT_96.txt",
|
||||||
|
"nf_fit_coeff": "pNFfit3.txt"
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
-1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01
|
|
||||||
-2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02
|
|
||||||
-1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01
|
|
||||||
-2.0500000000000000e+01 -2.0489473680000000e+01 -2.0478947370000000e+01 -2.0468421050000000e+01 -2.0457894740000000e+01 -2.0447368420000000e+01 -2.0436842110000001e+01 -2.0426315790000000e+01 -2.0415789470000000e+01 -2.0405263160000001e+01 -2.0394736840000000e+01 -2.0384210530000001e+01 -2.0373684210000000e+01 -2.0363157890000000e+01 -2.0352631580000001e+01 -2.0342105260000000e+01 -2.0331578950000001e+01 -2.0321052630000001e+01 -2.0310526320000001e+01 -2.0300000000000001e+01 -2.0289473680000000e+01 -2.0278947370000001e+01 -2.0268421050000001e+01 -2.0257894740000001e+01 -2.0247368420000001e+01 -2.0236842110000001e+01 -2.0226315790000001e+01 -2.0215789470000001e+01 -2.0205263160000001e+01 -2.0194736840000001e+01 -2.0184210530000001e+01 -2.0173684210000001e+01 -2.0163157890000001e+01 -2.0152631580000001e+01 -2.0142105260000001e+01 -2.0131578950000002e+01 -2.0121052630000001e+01 -2.0110526320000002e+01 -2.0100000000000001e+01 -2.0089473680000001e+01 -2.0078947370000002e+01 -2.0068421050000001e+01 -2.0057894739999998e+01 -2.0047368420000002e+01 -2.0036842109999998e+01 -2.0026315790000002e+01 -2.0015789470000001e+01 -2.0005263159999998e+01 -1.9994736840000002e+01 -1.9984210529999999e+01 -1.9973684209999998e+01 -1.9963157890000002e+01 -1.9952631579999998e+01 -1.9942105260000002e+01 -1.9931578949999999e+01 -1.9921052629999998e+01 -1.9910526319999999e+01 -1.9899999999999999e+01 -1.9889473679999998e+01 -1.9878947369999999e+01 -1.9868421049999998e+01 -1.9857894739999999e+01 -1.9847368419999999e+01 -1.9836842109999999e+01 -1.9826315789999999e+01 -1.9815789469999999e+01 -1.9805263159999999e+01 -1.9794736839999999e+01 -1.9784210529999999e+01 -1.9773684209999999e+01 -1.9763157889999999e+01 -1.9752631579999999e+01 -1.9742105259999999e+01 -1.9731578949999999e+01 -1.9721052629999999e+01 -1.9710526320000000e+01 -1.9699999999999999e+01 -1.9689473679999999e+01 -1.9678947369999999e+01 -1.9668421049999999e+01 -1.9657894740000000e+01 -1.9647368419999999e+01 -1.9636842110000000e+01 -1.9626315790000000e+01 -1.9615789469999999e+01 -1.9605263160000000e+01 -1.9594736839999999e+01 -1.9584210530000000e+01 -1.9573684210000000e+01 -1.9563157889999999e+01 -1.9552631580000000e+01 -1.9542105260000000e+01 -1.9531578950000000e+01 -1.9521052630000000e+01 -1.9510526320000000e+01 -1.9500000000000000e+01
|
|
||||||
-2.0500000000000000e+01 -2.0489473680000000e+01 -2.0478947370000000e+01 -2.0468421050000000e+01 -2.0457894740000000e+01 -2.0447368420000000e+01 -2.0436842110000001e+01 -2.0426315790000000e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.9573684210000000e+01 -1.9563157889999999e+01 -1.9552631580000000e+01 -1.9542105260000000e+01 -1.9531578950000000e+01 -1.9521052630000000e+01 -1.9510526320000000e+01 -1.9500000000000000e+01
|
|
||||||
-1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.4460000000000001e+01
|
|
||||||
-1.4460000000000001e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01
|
|
||||||
-1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.4460000000000001e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
7.0000000000000000e+01 1.1700000000000000e+02 1.0800000000000000e+02 1.0800000000000000e+02 3.2000000000000000e+01 7.0000000000000000e+01 1.0800000000000000e+02 9.7000000000000000e+01 1.1600000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01
|
|
||||||
7.9000000000000000e+01 1.1000000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 7.1000000000000000e+01 1.1400000000000000e+02 1.1100000000000000e+02 1.1700000000000000e+02 1.1200000000000000e+02 3.2000000000000000e+01 6.6000000000000000e+01 1.0800000000000000e+02 1.1700000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01
|
|
||||||
7.9000000000000000e+01 1.1000000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 7.1000000000000000e+01 1.1400000000000000e+02 1.1100000000000000e+02 1.1700000000000000e+02 1.1200000000000000e+02 3.2000000000000000e+01 8.2000000000000000e+01 1.0100000000000000e+02 1.0000000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01
|
|
||||||
7.0000000000000000e+01 1.1700000000000000e+02 1.0800000000000000e+02 1.0800000000000000e+02 3.2000000000000000e+01 1.1900000000000000e+02 3.2000000000000000e+01 8.3000000000000000e+01 8.2000000000000000e+01 8.3000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01
|
|
||||||
6.6000000000000000e+01 1.1100000000000000e+02 1.1600000000000000e+02 1.0400000000000000e+02 3.2000000000000000e+01 6.9000000000000000e+01 1.1000000000000000e+02 1.0000000000000000e+02 1.1500000000000000e+02 3.2000000000000000e+01 1.1900000000000000e+02 3.2000000000000000e+01 8.3000000000000000e+01 8.2000000000000000e+01 8.3000000000000000e+01
|
|
||||||
1.0400000000000000e+02 1.0100000000000000e+02 9.7000000000000000e+01 1.1800000000000000e+02 1.2100000000000000e+02 3.2000000000000000e+01 9.8000000000000000e+01 1.0800000000000000e+02 1.1700000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01
|
|
||||||
1.0400000000000000e+02 1.0100000000000000e+02 9.7000000000000000e+01 1.1800000000000000e+02 1.2100000000000000e+02 3.2000000000000000e+01 1.1400000000000000e+02 1.0100000000000000e+02 1.0000000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01
|
|
||||||
1.1900000000000000e+02 1.1100000000000000e+02 1.1400000000000000e+02 1.1500000000000000e+02 1.1600000000000000e+02 3.2000000000000000e+01 9.9000000000000000e+01 9.7000000000000000e+01 1.1500000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Created on Mon Nov 27 12:32:04 2017
|
|
||||||
|
|
||||||
@author: briantaylor
|
|
||||||
"""
|
|
||||||
import numpy as np
|
|
||||||
from numpy import polyfit, polyval, mean
|
|
||||||
from utilities import lin2db, db2lin, itufs, freq2wavelength
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
from scipy.constants import h
|
|
||||||
|
|
||||||
|
|
||||||
def noise_profile(nf, gain, ffs, df):
|
|
||||||
""" noise_profile(nf, gain, ffs, df) computes amplifier ase
|
|
||||||
|
|
||||||
:param nf: Noise figure in dB
|
|
||||||
:param gain: Actual gain calculated for the EDFA in dB units
|
|
||||||
:param ffs: A numpy array of frequencies
|
|
||||||
:param df: the reference bw in THz
|
|
||||||
:type nf: numpy.ndarray
|
|
||||||
:type gain: numpy.ndarray
|
|
||||||
:type ffs: numpy.ndarray
|
|
||||||
:type df: float
|
|
||||||
:return: the asepower in dBm
|
|
||||||
:rtype: numpy.ndarray
|
|
||||||
|
|
||||||
ASE POWER USING PER CHANNEL GAIN PROFILE
|
|
||||||
INPUTS:
|
|
||||||
NF_dB - Noise figure in dB, vector of length number of channels or
|
|
||||||
spectral slices
|
|
||||||
G_dB - Actual gain calculated for the EDFA, vector of length number of
|
|
||||||
channels or spectral slices
|
|
||||||
ffs - Center frequency grid of the channels or spectral slices in THz,
|
|
||||||
vector of length number of channels or spectral slices
|
|
||||||
dF - width of each channel or spectral slice in THz,
|
|
||||||
vector of length number of channels or spectral slices
|
|
||||||
OUTPUT:
|
|
||||||
ase_dBm - ase in dBm per channel or spectral slice
|
|
||||||
NOTE: the output is the total ASE in the channel or spectral slice. For
|
|
||||||
50GHz channels the ASE BW is effectively 0.4nm. To get to noise power in
|
|
||||||
0.1nm, subtract 6dB.
|
|
||||||
|
|
||||||
ONSR is usually quoted as channel power divided by
|
|
||||||
the ASE power in 0.1nm RBW, regardless of the width of the actual
|
|
||||||
channel. This is a historical convention from the days when optical
|
|
||||||
signals were much smaller (155Mbps, 2.5Gbps, ... 10Gbps) than the
|
|
||||||
resolution of the OSAs that were used to measure spectral power which
|
|
||||||
were set to 0.1nm resolution for convenience. Moving forward into
|
|
||||||
flexible grid and high baud rate signals, it may be convenient to begin
|
|
||||||
quoting power spectral density in the same BW for both signal and ASE,
|
|
||||||
e.g. 12.5GHz."""
|
|
||||||
|
|
||||||
h_mWThz = 1e-3 * h * (1e14)**2
|
|
||||||
nf_lin = db2lin(nf)
|
|
||||||
g_lin = db2lin(gain)
|
|
||||||
ase = h_mWThz * df * ffs * (nf_lin * g_lin - 1)
|
|
||||||
asedb = lin2db(ase)
|
|
||||||
|
|
||||||
return asedb
|
|
||||||
|
|
||||||
|
|
||||||
def gain_profile(dfg, dgt, Pin, gp, gtp):
|
|
||||||
"""
|
|
||||||
:param dfg: design flat gain
|
|
||||||
:param dgt: design gain tilt
|
|
||||||
:param Pin: channing input power profile
|
|
||||||
:param gp: Average gain setpoint in dB units
|
|
||||||
:param gtp: gain tilt setting
|
|
||||||
:type dfg: numpy.ndarray
|
|
||||||
:type dgt: numpy.ndarray
|
|
||||||
:type Pin: numpy.ndarray
|
|
||||||
:type gp: float
|
|
||||||
:type gtp: float
|
|
||||||
:return: gain profile in dBm
|
|
||||||
:rtype: numpy.ndarray
|
|
||||||
|
|
||||||
AMPLIFICATION USING INPUT PROFILE
|
|
||||||
INPUTS:
|
|
||||||
DFG - vector of length number of channels or spectral slices
|
|
||||||
DGT - vector of length number of channels or spectral slices
|
|
||||||
Pin - input powers vector of length number of channels or
|
|
||||||
spectral slices
|
|
||||||
Gp - provisioned gain length 1
|
|
||||||
GTp - provisioned tilt length 1
|
|
||||||
|
|
||||||
OUTPUT:
|
|
||||||
amp gain per channel or spectral slice
|
|
||||||
NOTE: there is no checking done for violations of the total output power
|
|
||||||
capability of the amp.
|
|
||||||
Ported from Matlab version written by David Boerges at Ciena.
|
|
||||||
Based on:
|
|
||||||
R. di Muro, "The Er3+ fiber gain coefficient derived from a dynamic
|
|
||||||
gain
|
|
||||||
tilt technique", Journal of Lightwave Technology, Vol. 18, Iss. 3,
|
|
||||||
Pp. 343-347, 2000.
|
|
||||||
"""
|
|
||||||
err_tolerance = 1.0e-11
|
|
||||||
simple_opt = True
|
|
||||||
|
|
||||||
# TODO make all values linear unit and convert to dB units as needed within
|
|
||||||
# this function.
|
|
||||||
nchan = list(range(len(Pin)))
|
|
||||||
|
|
||||||
# TODO find a way to use these or lose them. Primarily we should have a
|
|
||||||
# way to determine if exceeding the gain or output power of the amp
|
|
||||||
tot_in_power_db = lin2db(np.sum(db2lin(Pin)))
|
|
||||||
avg_gain_db = lin2db(mean(db2lin(dfg)))
|
|
||||||
|
|
||||||
# Linear fit to get the
|
|
||||||
p = polyfit(nchan, dgt, 1)
|
|
||||||
dgt_slope = p[0]
|
|
||||||
|
|
||||||
# Calculate the target slope- Currently assumes equal spaced channels
|
|
||||||
# TODO make it so that supports arbitrary channel spacing.
|
|
||||||
targ_slope = gtp / (len(nchan) - 1)
|
|
||||||
|
|
||||||
# 1st estimate of DGT scaling
|
|
||||||
dgts1 = targ_slope / dgt_slope
|
|
||||||
|
|
||||||
# when simple_opt is true code makes 2 attempts to compute gain and
|
|
||||||
# the internal voa value. This is currently here to provide direct
|
|
||||||
# comparison with original Matlab code. Will be removed.
|
|
||||||
# TODO replace with loop
|
|
||||||
|
|
||||||
if simple_opt:
|
|
||||||
|
|
||||||
# 1st estimate of Er gain & voa loss
|
|
||||||
g1st = dfg + dgt * dgts1
|
|
||||||
voa = lin2db(mean(db2lin(g1st))) - gp
|
|
||||||
|
|
||||||
# 2nd estimate of Amp ch gain using the channel input profile
|
|
||||||
g2nd = g1st - voa
|
|
||||||
pout_db = lin2db(np.sum(db2lin(Pin + g2nd)))
|
|
||||||
dgts2 = gp - (pout_db - tot_in_power_db)
|
|
||||||
|
|
||||||
# Center estimate of amp ch gain
|
|
||||||
xcent = dgts2
|
|
||||||
gcent = g1st - voa + dgt * xcent
|
|
||||||
pout_db = lin2db(np.sum(db2lin(Pin + gcent)))
|
|
||||||
gavg_cent = pout_db - tot_in_power_db
|
|
||||||
|
|
||||||
# Lower estimate of Amp ch gain
|
|
||||||
deltax = np.max(g1st) - np.min(g1st)
|
|
||||||
xlow = dgts2 - deltax
|
|
||||||
glow = g1st - voa + xlow * dgt
|
|
||||||
pout_db = lin2db(np.sum(db2lin(Pin + glow)))
|
|
||||||
gavg_low = pout_db - tot_in_power_db
|
|
||||||
|
|
||||||
# Upper gain estimate
|
|
||||||
xhigh = dgts2 + deltax
|
|
||||||
ghigh = g1st - voa + xhigh * dgt
|
|
||||||
pout_db = lin2db(np.sum(db2lin(Pin + ghigh)))
|
|
||||||
gavg_high = pout_db - tot_in_power_db
|
|
||||||
|
|
||||||
# compute slope
|
|
||||||
slope1 = (gavg_low - gavg_cent) / (xlow - xcent)
|
|
||||||
slope2 = (gavg_cent - gavg_high) / (xcent - xhigh)
|
|
||||||
|
|
||||||
if np.abs(gp - gavg_cent) <= err_tolerance:
|
|
||||||
dgts3 = xcent
|
|
||||||
elif gp < gavg_cent:
|
|
||||||
dgts3 = xcent - (gavg_cent - gp) / slope1
|
|
||||||
else:
|
|
||||||
dgts3 = xcent + (-gavg_cent + gp) / slope2
|
|
||||||
|
|
||||||
gprofile = g1st - voa + dgt * dgts3
|
|
||||||
else:
|
|
||||||
gprofile = None
|
|
||||||
|
|
||||||
return gprofile
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
plt.close('all')
|
|
||||||
fc = itufs(0.05)
|
|
||||||
lc = freq2wavelength(fc) / 1000
|
|
||||||
nchan = list(range(len(lc)))
|
|
||||||
df = np.array([0.05] * (nchan[-1] + 1))
|
|
||||||
# TODO remove path dependence
|
|
||||||
path = ''
|
|
||||||
|
|
||||||
"""
|
|
||||||
DFG_96: Design flat gain at each wavelength in the 96 channel 50GHz ITU
|
|
||||||
grid in dB. This can be experimentally determined by measuring the gain
|
|
||||||
at each wavelength using a full, flat channel (or ASE) load at the input.
|
|
||||||
The amplifier should be set to its maximum flat gain (tilt = 0dB). This
|
|
||||||
measurement captures the ripple of the amplifier. If the amplifier was
|
|
||||||
designed to be mimimum ripple at some other tilt value, then the ripple
|
|
||||||
reflected in this measurement will not be that minimum. However, when
|
|
||||||
the DGT gets applied through the provisioning of tilt, the model should
|
|
||||||
accurately reproduce the expected ripple at that tilt value. One could
|
|
||||||
also do the measurement at some expected tilt value and back-calculate
|
|
||||||
this vector using the DGT method. Alternatively, one could re-write the
|
|
||||||
algorithm to accept a nominal tilt and a tiled version of this vector.
|
|
||||||
"""
|
|
||||||
|
|
||||||
dfg_96 = np.loadtxt(path + 'DFG_96.txt')
|
|
||||||
|
|
||||||
"""maximum gain for flat operation - the amp in the data file was designed
|
|
||||||
for 25dB gain and has an internal VOA for setting the external gain
|
|
||||||
"""
|
|
||||||
|
|
||||||
avg_dfg = dfg_96.mean()
|
|
||||||
|
|
||||||
"""
|
|
||||||
DGT_96: This is the so-called Dynamic Gain Tilt of the EDFA in dB/dB. It
|
|
||||||
is the change in gain at each wavelength corresponding to a 1dB change at
|
|
||||||
the longest wavelength supported. The value can be obtained
|
|
||||||
experimentally or through analysis of the cross sections or Giles
|
|
||||||
parameters of the Er fibre. This is experimentally measured by changing
|
|
||||||
the gain of the amplifier above the maximum flat gain while not changing
|
|
||||||
the internal VOA (i.e. the mid-stage VOA is set to minimum and does not
|
|
||||||
change during the measurement). Note that the measurement can change the
|
|
||||||
gain by an arbitrary amount and divide by the gain change (in dB) which
|
|
||||||
is measured at the reference wavelength (the red end of the band).
|
|
||||||
"""
|
|
||||||
|
|
||||||
dgt_96 = np.loadtxt(path + 'DGT_96.txt')
|
|
||||||
|
|
||||||
"""
|
|
||||||
pNFfit3: Cubic polynomial fit coefficients to noise figure in dB
|
|
||||||
averaged across wavelength as a function of gain change from design flat:
|
|
||||||
|
|
||||||
NFavg = pNFfit3(1)*dG^3 + pNFfit3(2)*dG^2 pNFfit3(3)*dG + pNFfit3(4)
|
|
||||||
where
|
|
||||||
dG = GainTarget - average(DFG_96)
|
|
||||||
note that dG will normally be a negative value.
|
|
||||||
"""
|
|
||||||
|
|
||||||
nf_fitco = np.loadtxt(path + 'pNFfit3.txt')
|
|
||||||
|
|
||||||
"""NFR_96: Noise figure ripple in dB away from the average noise figure
|
|
||||||
across the band. This captures the wavelength dependence of the NF. To
|
|
||||||
calculate the NF across channels, one uses the cubic fit coefficients
|
|
||||||
with the external gain target to get the average nosie figure, NFavg and
|
|
||||||
then adds this to NFR_96:
|
|
||||||
NF_96 = NFR_96 + NFavg
|
|
||||||
"""
|
|
||||||
|
|
||||||
nf_ripple = np.loadtxt(path + 'NFR_96.txt')
|
|
||||||
|
|
||||||
# This is an example to set the provisionable gain and gain-tilt values
|
|
||||||
# Tilt is in units of dB/THz
|
|
||||||
gain_target = 20.0
|
|
||||||
tilt_target = -0.7
|
|
||||||
|
|
||||||
# calculate the NF for the EDFA at this gain setting
|
|
||||||
dg = gain_target - avg_dfg
|
|
||||||
nf_avg = polyval(nf_fitco, dg)
|
|
||||||
nf_96 = nf_ripple + nf_avg
|
|
||||||
|
|
||||||
# get the input power profiles to show
|
|
||||||
pch2d = np.loadtxt(path + 'Pchan2D.txt')
|
|
||||||
|
|
||||||
# Load legend and assemble legend text
|
|
||||||
pch2d_legend_data = np.loadtxt(path + 'Pchan2DLegend.txt')
|
|
||||||
pch2d_legend = []
|
|
||||||
for ea in pch2d_legend_data:
|
|
||||||
s = ''.join([chr(xx) for xx in ea.astype(dtype=int)]).strip()
|
|
||||||
pch2d_legend.append(s)
|
|
||||||
|
|
||||||
# assemble plot
|
|
||||||
axis_font = {'fontname': 'Arial', 'size': '16', 'fontweight': 'bold'}
|
|
||||||
title_font = {'fontname': 'Arial', 'size': '17', 'fontweight': 'bold'}
|
|
||||||
tic_font = {'fontname': 'Arial', 'size': '12'}
|
|
||||||
|
|
||||||
plt.rcParams["font.family"] = "Arial"
|
|
||||||
plt.figure()
|
|
||||||
plt.plot(nchan, pch2d.T, '.-', lw=2)
|
|
||||||
plt.xlabel('Channel Number', **axis_font)
|
|
||||||
plt.ylabel('Channel Power [dBm]', **axis_font)
|
|
||||||
plt.title('Input Power Profiles for Different Channel Loading',
|
|
||||||
**title_font)
|
|
||||||
plt.legend(pch2d_legend, loc=5)
|
|
||||||
plt.grid()
|
|
||||||
plt.ylim((-100, -10))
|
|
||||||
plt.xlim((0, 110))
|
|
||||||
plt.xticks(np.arange(0, 100, 10), **tic_font)
|
|
||||||
plt.yticks(np.arange(-110, -10, 10), **tic_font)
|
|
||||||
|
|
||||||
plt.figure()
|
|
||||||
ea = pch2d[1, :]
|
|
||||||
for ea in pch2d:
|
|
||||||
chgain = gain_profile(dfg_96, dgt_96, ea, gain_target, tilt_target)
|
|
||||||
pase = noise_profile(nf_96, chgain, fc, df)
|
|
||||||
pout = lin2db(db2lin(ea + chgain) + db2lin(pase))
|
|
||||||
plt.plot(nchan, pout, '.-', lw=2)
|
|
||||||
plt.title('Output Power with ASE for Different Channel Loading',
|
|
||||||
**title_font)
|
|
||||||
plt.xlabel('Channel Number', **axis_font)
|
|
||||||
plt.ylabel('Channel Power [dBm]', **axis_font)
|
|
||||||
plt.grid()
|
|
||||||
plt.ylim((-50, 10))
|
|
||||||
plt.xlim((0, 100))
|
|
||||||
plt.xticks(np.arange(0, 100, 10), **tic_font)
|
|
||||||
plt.yticks(np.arange(-50, 10, 10), **tic_font)
|
|
||||||
plt.legend(pch2d_legend, loc=5)
|
|
||||||
plt.show()
|
|
||||||
300
examples/edfa_model/amplifier_models_description.rst
Normal file
300
examples/edfa_model/amplifier_models_description.rst
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
*********************************************
|
||||||
|
Amplifier models and configuration
|
||||||
|
*********************************************
|
||||||
|
|
||||||
|
|
||||||
|
1. Equipment configuration description
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
Equipment description defines equipment types and parameters.
|
||||||
|
It takes place in the default **eqpt_config.json** file.
|
||||||
|
By default **transmission_main_example.py** uses **eqpt_config.json** file and that
|
||||||
|
can be changed with **-e** or **--equipment** command line parameter.
|
||||||
|
|
||||||
|
2. Amplifier parameters and subtypes
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
Several amplifiers can be used by GNpy, so they are defined as an array of equipment parameters in **eqpt_config.json** file.
|
||||||
|
|
||||||
|
- *"type_variety"*:
|
||||||
|
Each amplifier is identified by its unique *"type_variety"*, which is used in the topology files input to reference a specific amplifier. It is a user free defined id.
|
||||||
|
|
||||||
|
For each amplifier *type_variety*, specific parameters are describing its attributes and performance:
|
||||||
|
|
||||||
|
- *"type_def"*:
|
||||||
|
Sets the amplifier model that the simulation will use to calculate the ase noise contribution. 5 models are defined with reserved words:
|
||||||
|
|
||||||
|
- *"advanced_model"*
|
||||||
|
- *"variable_gain"*
|
||||||
|
- *"fixed_gain"*
|
||||||
|
- *"dual_stage"*
|
||||||
|
- *"openroadm"*
|
||||||
|
*see next section for a full description of these models*
|
||||||
|
|
||||||
|
- *"advanced_config_from_json"*:
|
||||||
|
**This parameter is only applicable to the _"advanced_model"_ model**
|
||||||
|
|
||||||
|
json file name describing:
|
||||||
|
|
||||||
|
- nf_fit_coeff
|
||||||
|
- f_min/max
|
||||||
|
- gain_ripple
|
||||||
|
- nf_ripple
|
||||||
|
- dgt
|
||||||
|
|
||||||
|
*see next section for a full description*
|
||||||
|
|
||||||
|
- *"gain_flatmax"*:
|
||||||
|
amplifier maximum gain in dB before its extended gain range: flat or nominal tilt output.
|
||||||
|
|
||||||
|
If gain > gain_flatmax, the amplifier will tilt, based on its dgt function
|
||||||
|
|
||||||
|
If gain > gain_flatmax + target_extended_gain, the amplifier output power is reduced to not exceed the extended gain range.
|
||||||
|
|
||||||
|
- *"gain_min"*:
|
||||||
|
amplifier minimum gain in dB.
|
||||||
|
|
||||||
|
If gain < gain_min, the amplifier input is automatically padded, which results in
|
||||||
|
|
||||||
|
NF += gain_min - gain
|
||||||
|
|
||||||
|
- *"p_max"*:
|
||||||
|
amplifier max output power, full load
|
||||||
|
|
||||||
|
Total signal output power will not be allowed beyond this value
|
||||||
|
|
||||||
|
- *"nf_min/max"*:
|
||||||
|
**These parameters are only applicable to the _"variable_gain"_ model**
|
||||||
|
|
||||||
|
min & max NF values in dB
|
||||||
|
|
||||||
|
NF_min is the amplifier NF @ gain_max
|
||||||
|
|
||||||
|
NF_max is the amplifier NF @ gain_min
|
||||||
|
|
||||||
|
- *"nf_coef"*:
|
||||||
|
**This parameter is only applicable to the *"openroadm"* model**
|
||||||
|
|
||||||
|
[a, b, c, d] 3rd order polynomial coefficients list to define the incremental OSNR vs Pin
|
||||||
|
|
||||||
|
Incremental OSNR is the amplifier OSNR contribution
|
||||||
|
|
||||||
|
Pin is the amplifier channel input power defined in a 50GHz bandwidth
|
||||||
|
|
||||||
|
Incremental OSNR = a*Pin³ + b*Pin² + c*Pin + d
|
||||||
|
|
||||||
|
- *"preamp_variety"*:
|
||||||
|
**This parameter is only applicable to the _"dual_stage"_ model**
|
||||||
|
|
||||||
|
1st stage type_variety
|
||||||
|
|
||||||
|
- *"booster_variety"*:
|
||||||
|
**This parameter is only applicable to the *"dual_stage"* model**
|
||||||
|
|
||||||
|
2nd stage type_variety
|
||||||
|
|
||||||
|
- *"out_voa_auto"*: true/false
|
||||||
|
**power_mode only**
|
||||||
|
|
||||||
|
**This parameter is only applicable to the *"advanced_model"* and *"variable_gain"* models**
|
||||||
|
|
||||||
|
If "out_voa_auto": true, auto_design will chose the output_VOA value that maximizes the amplifier gain within its power capability and therefore minimizes its NF.
|
||||||
|
|
||||||
|
- *"allowed_for_design"*: true/false
|
||||||
|
**auto_design only**
|
||||||
|
|
||||||
|
Tells auto_design if this amplifier can be picked for the design (deactivates unwanted amplifiers)
|
||||||
|
|
||||||
|
It does not prevent the use of an amplifier if it is placed in the topology input.
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{"Edfa": [{
|
||||||
|
"type_variety": "std_medium_gain",
|
||||||
|
"type_def": "variable_gain",
|
||||||
|
"gain_flatmax": 26,
|
||||||
|
"gain_min": 15,
|
||||||
|
"p_max": 23,
|
||||||
|
"nf_min": 6,
|
||||||
|
"nf_max": 10,
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"type_def": "variable_gain",
|
||||||
|
"gain_flatmax": 16,
|
||||||
|
"gain_min": 8,
|
||||||
|
"p_max": 23,
|
||||||
|
"nf_min": 6.5,
|
||||||
|
"nf_max": 11,
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": true
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
|
||||||
|
|
||||||
|
3. Amplifier models
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
In an opensource and multi-vendor environnement, it is needed to support different use cases and context. Therefore several models are supported for amplifiers.
|
||||||
|
|
||||||
|
5 types of EDFA definition are possible and referenced by the *"type_def"* parameter with the following reserved words:
|
||||||
|
|
||||||
|
- *"advanced_model"*
|
||||||
|
This model is refered as a whitebox model because of the detailed level of knowledge that is required. The amplifier NF model and ripple definition are described by a json file referenced with *"advanced_config_from_json"*: json filename. This json file contains:
|
||||||
|
|
||||||
|
- nf_fit_coeff: [a,b,c,d]
|
||||||
|
|
||||||
|
3rd order polynomial NF = f(-dg) coeficients list
|
||||||
|
|
||||||
|
dg = gain - gain_max
|
||||||
|
|
||||||
|
- f_min/max: amplifier frequency range in Hz
|
||||||
|
- gain_ripple : [...]
|
||||||
|
|
||||||
|
amplifier gain ripple excursion comb list in dB across the frequency range.
|
||||||
|
- nf_ripple : [...]
|
||||||
|
|
||||||
|
amplifier nf ripple excursion comb list in dB across the frequency range.
|
||||||
|
- dgt : [...]
|
||||||
|
amplifier dynamic gain tilt comb list across the frequency range.
|
||||||
|
|
||||||
|
*See next section for the generation of this json file*
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
|
"Edfa":[{
|
||||||
|
"type_variety": "high_detail_model_example",
|
||||||
|
"type_def": "advanced_model",
|
||||||
|
"gain_flatmax": 25,
|
||||||
|
"gain_min": 15,
|
||||||
|
"p_max": 21,
|
||||||
|
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
- *"variable_gain"*
|
||||||
|
This model is refered as an operator model because a lower level of knowledge is required. A full polynomial description of the NF cross the gain range is not required. Instead, NF_min and NF_max values are required and used by the code to model a dual stage amplifier with an internal mid stage VOA. NF_min and NF_max values are typically available from equipment suppliers data-sheet.
|
||||||
|
|
||||||
|
There is a default JSON file ”default_edfa_config.json”* to enforce 0 tilt and ripple values because GNpy core algorithm is a multi-carrier propogation.
|
||||||
|
- gain_ripple =[0,...,0]
|
||||||
|
- nf_ripple = [0,...,0]
|
||||||
|
- dgt = [...] generic dgt comb
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
|
"Edfa":[{
|
||||||
|
"type_variety": "std_medium_gain",
|
||||||
|
"type_def": "variable_gain",
|
||||||
|
"gain_flatmax": 26,
|
||||||
|
"gain_min": 15,
|
||||||
|
"p_max": 23,
|
||||||
|
"nf_min": 6,
|
||||||
|
"nf_max": 10,
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
- *"fixed_gain"*
|
||||||
|
This model is also an operator model with a single NF value that emulates basic single coil amplifiers without internal VOA.
|
||||||
|
|
||||||
|
if gain_min < gain < gain_max, NF == nf0
|
||||||
|
|
||||||
|
if gain < gain_min, the amplifier input is automatically padded, which results in
|
||||||
|
|
||||||
|
NF += gain_min - gain
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
|
"Edfa":[{
|
||||||
|
"type_variety": "std_fixed_gain",
|
||||||
|
"type_def": "fixed_gain",
|
||||||
|
"gain_flatmax": 21,
|
||||||
|
"gain_min": 20,
|
||||||
|
"p_max": 21,
|
||||||
|
"nf0": 5.5,
|
||||||
|
"allowed_for_design": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
- *"openroadm"*
|
||||||
|
This model is a black box model replicating OpenRoadm MSA spec for ILA.
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
|
"Edfa":[{
|
||||||
|
"type_variety": "low_noise",
|
||||||
|
"type_def": "openroadm",
|
||||||
|
"gain_flatmax": 27,
|
||||||
|
"gain_min": 12,
|
||||||
|
"p_max": 22,
|
||||||
|
"nf_coef": [-8.104e-4,-6.221e-2,-5.889e-1,37.62],
|
||||||
|
"allowed_for_design": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
- *"dual_stage"*
|
||||||
|
This model allows the cascade (pre-defined combination) of any 2 amplifiers already described in the eqpt_config.json library.
|
||||||
|
|
||||||
|
- preamp_variety defines the 1st stge type variety
|
||||||
|
|
||||||
|
- booster variety defines the 2nd stage type variety
|
||||||
|
|
||||||
|
Both preamp and booster variety must exist in the eqpt libray
|
||||||
|
The resulting NF is the sum of the 2 amplifiers
|
||||||
|
The preamp is operated to its maximum gain
|
||||||
|
|
||||||
|
- gain_min indicates to auto_design when this dual_stage should be used
|
||||||
|
|
||||||
|
But unlike other models the 1st stage input will not be padded: it is always operated to its maximu gain and min NF. Therefore if gain adaptation and padding is needed it will be performed by the 2nd stage.
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"type_variety": "medium+low_gain",
|
||||||
|
"type_def": "dual_stage",
|
||||||
|
"gain_min": 25,
|
||||||
|
"preamp_variety": "std_medium_gain",
|
||||||
|
"booster_variety": "std_low_gain",
|
||||||
|
"allowed_for_design": true
|
||||||
|
}
|
||||||
|
|
||||||
|
4. advanced_config_from_json
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
The build_oa_json.py library in gnpy/examples/edfa_model can be used to build the json file required for the amplifier advanced_model type_def:
|
||||||
|
|
||||||
|
Update an existing json file with all the 96ch txt files for a given amplifier type
|
||||||
|
amplifier type 'OA_type1' is hard coded but can be modified and other types added
|
||||||
|
returns an updated amplifier json file: output_json_file_name = 'edfa_config.json'
|
||||||
|
amplifier file names
|
||||||
|
|
||||||
|
Convert a set of amplifier files + input json definiton file into a valid edfa_json_file:
|
||||||
|
|
||||||
|
nf_fit_coeff: NF 3rd order polynomial coefficients txt file
|
||||||
|
|
||||||
|
nf = f(dg) with dg = gain_operational - gain_max
|
||||||
|
|
||||||
|
nf_ripple: NF ripple excursion txt file
|
||||||
|
|
||||||
|
gain_ripple: gain ripple txt file
|
||||||
|
|
||||||
|
dgt: dynamic gain txt file
|
||||||
|
|
||||||
|
input json file in argument (defult = 'OA.json')
|
||||||
|
|
||||||
|
the json input file should have the following fields:
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"nf_fit_coeff": "nf_filename.txt",
|
||||||
|
"nf_ripple": "nf_ripple_filename.txt",
|
||||||
|
"gain_ripple": "DFG_filename.txt",
|
||||||
|
"dgt": "DGT_filename.txt"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
Created on Tue Jan 30 12:32:00 2018
|
Created on Tue Jan 30 12:32:00 2018
|
||||||
|
|
||||||
@author: jeanluc-auge
|
@author: jeanluc-auge
|
||||||
@comments about amplifier input files from Brian Taylor & Dave Boertjes
|
|
||||||
|
|
||||||
update an existing json file with all the 96ch txt files for a given amplifier type
|
update an existing json file with all the 96ch txt files for a given amplifier type
|
||||||
amplifier type 'OA_type1' is hard coded but can be modified and other types added
|
amplifier type 'OA_type1' is hard coded but can be modified and other types added
|
||||||
@@ -18,46 +17,29 @@ from gnpy.core.utils import lin2db, db2lin
|
|||||||
|
|
||||||
"""amplifier file names
|
"""amplifier file names
|
||||||
convert a set of amplifier files + input json definiton file into a valid edfa_json_file:
|
convert a set of amplifier files + input json definiton file into a valid edfa_json_file:
|
||||||
nf_fit_coeff: NF polynomial coefficients txt file (optional)
|
nf_fit_coeff: NF 3rd order polynomial coefficients txt file
|
||||||
|
nf = f(dg)
|
||||||
|
with dg = gain_operational - gain_max
|
||||||
nf_ripple: NF ripple excursion txt file
|
nf_ripple: NF ripple excursion txt file
|
||||||
dfg: gain txt file
|
gain_ripple: gain ripple txt file
|
||||||
dgt: dynamic gain txt file
|
dgt: dynamic gain txt file
|
||||||
input json file in argument (defult = 'OA.json')
|
input json file in argument (defult = 'OA.json')
|
||||||
|
|
||||||
the json input file should have the following fields:
|
the json input file should have the following fields:
|
||||||
{
|
{
|
||||||
"gain_flatmax": 25,
|
"nf_fit_coeff": "nf_filename.txt",
|
||||||
"gain_min": 15,
|
"nf_ripple": "nf_ripple_filename.txt",
|
||||||
"p_max": 21,
|
"gain_ripple": "DFG_filename.txt",
|
||||||
"nf_fit_coeff": "pNFfit3.txt",
|
"dgt": "DGT_filename.txt",
|
||||||
"nf_ripple": "NFR_96.txt",
|
|
||||||
"dfg": "DFG_96.txt",
|
|
||||||
"dgt": "DGT_96.txt",
|
|
||||||
"nf_model":
|
|
||||||
{
|
|
||||||
"enabled": true,
|
|
||||||
"nf_min": 5.8,
|
|
||||||
"nf_max": 10
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
gain_flat = max flat gain (dB)
|
|
||||||
gain_min = min gain (dB) : will consider an input VOA if below (TBD vs throwing an exception)
|
|
||||||
p_max = max power (dBm)
|
|
||||||
nf_fit = boolean (True, False) :
|
|
||||||
if False nf_fit_coeff are ignored and nf_model fields are used
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
input_json_file_name = "OA.json" #default path
|
input_json_file_name = "OA.json" #default path
|
||||||
output_json_file_name = "default_edfa_config.json"
|
output_json_file_name = "default_edfa_config.json"
|
||||||
param_field ="params"
|
gain_ripple_field = "gain_ripple"
|
||||||
gain_min_field = "gain_min"
|
|
||||||
gain_max_field = "gain_flatmax"
|
|
||||||
gain_ripple_field = "dfg"
|
|
||||||
nf_ripple_field = "nf_ripple"
|
nf_ripple_field = "nf_ripple"
|
||||||
nf_fit_coeff = "nf_fit_coeff"
|
nf_fit_coeff = "nf_fit_coeff"
|
||||||
nf_model_field = "nf_model"
|
|
||||||
nf_model_enabled_field = "enabled"
|
|
||||||
nf_min_field ="nf_min"
|
|
||||||
nf_max_field = "nf_max"
|
|
||||||
|
|
||||||
def read_file(field, file_name):
|
def read_file(field, file_name):
|
||||||
"""read and format the 96 channels txt files describing the amplifier NF and ripple
|
"""read and format the 96 channels txt files describing the amplifier NF and ripple
|
||||||
@@ -76,6 +58,7 @@ def read_file(field, file_name):
|
|||||||
#consider ripple excursion only to avoid redundant information
|
#consider ripple excursion only to avoid redundant information
|
||||||
#because the max flat_gain is already given by the 'gain_flat' field in json
|
#because the max flat_gain is already given by the 'gain_flat' field in json
|
||||||
#remove the mean component
|
#remove the mean component
|
||||||
|
print(file_name, ', mean value =', data.mean(), ' is substracted')
|
||||||
data = data - data.mean()
|
data = data - data.mean()
|
||||||
data = data.tolist()
|
data = data.tolist()
|
||||||
return data
|
return data
|
||||||
|
|||||||
@@ -1,313 +0,0 @@
|
|||||||
{
|
|
||||||
"params": {
|
|
||||||
"gain_flatmax": 25,
|
|
||||||
"gain_min": 15,
|
|
||||||
"p_max": 21,
|
|
||||||
"nf_fit_coeff": [
|
|
||||||
0.000168241,
|
|
||||||
0.0469961,
|
|
||||||
0.0359549,
|
|
||||||
5.82851
|
|
||||||
],
|
|
||||||
"nf_ripple": [
|
|
||||||
-0.3110761646066259,
|
|
||||||
-0.3110761646066259,
|
|
||||||
-0.31110274831665313,
|
|
||||||
-0.31419329378173544,
|
|
||||||
-0.3172854168606314,
|
|
||||||
-0.32037911876162584,
|
|
||||||
-0.3233255190215882,
|
|
||||||
-0.31624321721895354,
|
|
||||||
-0.30915729645781326,
|
|
||||||
-0.30206775396360075,
|
|
||||||
-0.2949045115165272,
|
|
||||||
-0.26632156113294336,
|
|
||||||
-0.23772399031437283,
|
|
||||||
-0.20911178784023846,
|
|
||||||
-0.18048410390821285,
|
|
||||||
-0.14379944379052215,
|
|
||||||
-0.10709599992470213,
|
|
||||||
-0.07037375788020579,
|
|
||||||
-0.03372858157230583,
|
|
||||||
-0.015660302006048,
|
|
||||||
0.0024172385953583004,
|
|
||||||
0.020504047353947653,
|
|
||||||
0.03860013139908377,
|
|
||||||
0.05670549786742816,
|
|
||||||
0.07482015390297145,
|
|
||||||
0.0838762040768461,
|
|
||||||
0.09284481475528361,
|
|
||||||
0.1018180306253394,
|
|
||||||
0.11079585523492333,
|
|
||||||
0.1020395478432815,
|
|
||||||
0.09310160456603413,
|
|
||||||
0.08415906712621996,
|
|
||||||
0.07521193198077789,
|
|
||||||
0.0676340601339394,
|
|
||||||
0.06005437964543287,
|
|
||||||
0.052470799141237305,
|
|
||||||
0.044883315610536455,
|
|
||||||
0.037679759069084225,
|
|
||||||
0.03047647598902483,
|
|
||||||
0.02326948274513522,
|
|
||||||
0.01605877647020772,
|
|
||||||
0.021248462316134083,
|
|
||||||
0.02657315875107553,
|
|
||||||
0.03190060058247842,
|
|
||||||
0.03723078993416436,
|
|
||||||
0.04256372893215024,
|
|
||||||
0.047899419704645264,
|
|
||||||
0.03915515813685565,
|
|
||||||
0.030289222542492025,
|
|
||||||
0.021418708618354456,
|
|
||||||
0.012573926129294415,
|
|
||||||
0.006240488799898697,
|
|
||||||
-9.622162373026585e-05,
|
|
||||||
-0.006436207679519103,
|
|
||||||
-0.012779471908040341,
|
|
||||||
-0.02038153550619876,
|
|
||||||
-0.027999803010447587,
|
|
||||||
-0.035622012697103154,
|
|
||||||
-0.043236398934156144,
|
|
||||||
-0.04493583574805963,
|
|
||||||
-0.04663615264317309,
|
|
||||||
-0.048337350303318156,
|
|
||||||
-0.050039429413028365,
|
|
||||||
-0.051742390657545205,
|
|
||||||
-0.05342028484370278,
|
|
||||||
-0.05254242298580185,
|
|
||||||
-0.05166410580536087,
|
|
||||||
-0.05078533294804249,
|
|
||||||
-0.04990610405914272,
|
|
||||||
-0.05409792133358102,
|
|
||||||
-0.05832916277634124,
|
|
||||||
-0.06256260169582961,
|
|
||||||
-0.06660356886269536,
|
|
||||||
-0.04779792991567815,
|
|
||||||
-0.028982516728038848,
|
|
||||||
-0.010157321677553965,
|
|
||||||
0.00861320615127981,
|
|
||||||
0.01913736978785662,
|
|
||||||
0.029667009055877668,
|
|
||||||
0.04020212822983975,
|
|
||||||
0.050742731588695494,
|
|
||||||
0.061288823415841555,
|
|
||||||
0.07184040799914815,
|
|
||||||
0.1043252636301016,
|
|
||||||
0.13687829834471027,
|
|
||||||
0.1694483010211072,
|
|
||||||
0.202035284929368,
|
|
||||||
0.23624619427167134,
|
|
||||||
0.27048596623174515,
|
|
||||||
0.30474360397422756,
|
|
||||||
0.3390191214858807,
|
|
||||||
0.36358851509924695,
|
|
||||||
0.38814205928193013,
|
|
||||||
0.41270842850729195,
|
|
||||||
0.4372876328262819,
|
|
||||||
0.4372876328262819
|
|
||||||
],
|
|
||||||
"dgt": [
|
|
||||||
2.714526681131686,
|
|
||||||
2.705443819238505,
|
|
||||||
2.6947834587664494,
|
|
||||||
2.6841217449620203,
|
|
||||||
2.6681935771243177,
|
|
||||||
2.6521732021128046,
|
|
||||||
2.630396440815385,
|
|
||||||
2.602860350286428,
|
|
||||||
2.5696460593920065,
|
|
||||||
2.5364027376452056,
|
|
||||||
2.499446286796604,
|
|
||||||
2.4587748041127506,
|
|
||||||
2.414398437185221,
|
|
||||||
2.3699990328716107,
|
|
||||||
2.322373696229342,
|
|
||||||
2.271520771371253,
|
|
||||||
2.2174389328192197,
|
|
||||||
2.16337565384239,
|
|
||||||
2.1183028432496016,
|
|
||||||
2.082225099873648,
|
|
||||||
2.055100772005235,
|
|
||||||
2.0279625371819305,
|
|
||||||
2.0008103857988204,
|
|
||||||
1.9736443063300082,
|
|
||||||
1.9482128147680253,
|
|
||||||
1.9245345552113182,
|
|
||||||
1.9026104247588487,
|
|
||||||
1.8806927939516411,
|
|
||||||
1.862235672444246,
|
|
||||||
1.847275503201129,
|
|
||||||
1.835814081380705,
|
|
||||||
1.824381436842932,
|
|
||||||
1.8139629377087627,
|
|
||||||
1.8045606557581335,
|
|
||||||
1.7961751115773796,
|
|
||||||
1.7877868031023945,
|
|
||||||
1.7793941781790852,
|
|
||||||
1.7709972329654864,
|
|
||||||
1.7625959636196327,
|
|
||||||
1.7541903672600494,
|
|
||||||
1.7459181197626403,
|
|
||||||
1.737780757913635,
|
|
||||||
1.7297783508684146,
|
|
||||||
1.7217732861435076,
|
|
||||||
1.7137640932265894,
|
|
||||||
1.7057507692361864,
|
|
||||||
1.6918150918099673,
|
|
||||||
1.6719047669939942,
|
|
||||||
1.6460167077689267,
|
|
||||||
1.6201194134191075,
|
|
||||||
1.5986915141218316,
|
|
||||||
1.5817353179379183,
|
|
||||||
1.569199764184379,
|
|
||||||
1.5566577309558969,
|
|
||||||
1.545374152761467,
|
|
||||||
1.5353620432989845,
|
|
||||||
1.5266220576235803,
|
|
||||||
1.5178910621476225,
|
|
||||||
1.5097346239790443,
|
|
||||||
1.502153039909686,
|
|
||||||
1.495145456062699,
|
|
||||||
1.488134243479226,
|
|
||||||
1.48111939735681,
|
|
||||||
1.474100442252211,
|
|
||||||
1.4670307626366115,
|
|
||||||
1.4599103316162523,
|
|
||||||
1.45273959485914,
|
|
||||||
1.445565137158368,
|
|
||||||
1.4340878115214444,
|
|
||||||
1.418273806730323,
|
|
||||||
1.3981208704326855,
|
|
||||||
1.3779439775587023,
|
|
||||||
1.3598972673004606,
|
|
||||||
1.3439818461440451,
|
|
||||||
1.3301807335621048,
|
|
||||||
1.316383926863083,
|
|
||||||
1.3040618749785347,
|
|
||||||
1.2932153453410835,
|
|
||||||
1.2838336236692311,
|
|
||||||
1.2744470198196236,
|
|
||||||
1.2650555289898042,
|
|
||||||
1.2556591482982988,
|
|
||||||
1.2428104897182262,
|
|
||||||
1.2264996957264114,
|
|
||||||
1.2067249615595257,
|
|
||||||
1.1869318618366975,
|
|
||||||
1.1672278304018044,
|
|
||||||
1.1476135933863398,
|
|
||||||
1.1280891949729075,
|
|
||||||
1.108555289615659,
|
|
||||||
1.0895983485572227,
|
|
||||||
1.0712204022764056,
|
|
||||||
1.0534217504465226,
|
|
||||||
1.0356155337864215,
|
|
||||||
1.017807767853702,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"nf_model": {
|
|
||||||
"enabled": true,
|
|
||||||
"nf1": 5.727887800964238,
|
|
||||||
"nf2": 7.727887800964238,
|
|
||||||
"delta_p": 5.238350271545567
|
|
||||||
},
|
|
||||||
"gain_ripple": [
|
|
||||||
0.1359703369791596,
|
|
||||||
0.11822862697916037,
|
|
||||||
0.09542181697916163,
|
|
||||||
0.06245819697916133,
|
|
||||||
0.02602813697916062,
|
|
||||||
-0.0036199830208403228,
|
|
||||||
-0.018326963020840026,
|
|
||||||
-0.0246928330208398,
|
|
||||||
-0.016792253020838643,
|
|
||||||
-0.0028138630208403015,
|
|
||||||
0.017572956979162058,
|
|
||||||
0.038328296979159404,
|
|
||||||
0.054956336979159914,
|
|
||||||
0.0670723869791594,
|
|
||||||
0.07091459697916136,
|
|
||||||
0.07094413697916124,
|
|
||||||
0.07114372697916238,
|
|
||||||
0.07533675697916209,
|
|
||||||
0.08731066697916035,
|
|
||||||
0.10313984697916112,
|
|
||||||
0.12276252697916235,
|
|
||||||
0.14239527697916188,
|
|
||||||
0.15945681697916214,
|
|
||||||
0.1739275269791598,
|
|
||||||
0.1767381569791624,
|
|
||||||
0.17037189697916233,
|
|
||||||
0.15216302697916007,
|
|
||||||
0.13114358697916018,
|
|
||||||
0.10802383697916085,
|
|
||||||
0.08548825697916129,
|
|
||||||
0.06916723697916183,
|
|
||||||
0.05848224697916038,
|
|
||||||
0.05447361697916264,
|
|
||||||
0.05154489697916276,
|
|
||||||
0.04946107697915991,
|
|
||||||
0.04717897697916129,
|
|
||||||
0.04551704697916037,
|
|
||||||
0.04467697697916151,
|
|
||||||
0.04072968697916224,
|
|
||||||
0.03285456697916089,
|
|
||||||
0.023488786979161347,
|
|
||||||
0.01659282697915998,
|
|
||||||
0.013321846979160057,
|
|
||||||
0.011234826979162449,
|
|
||||||
0.01030063697916006,
|
|
||||||
0.00936596697916059,
|
|
||||||
0.00874012697916271,
|
|
||||||
0.00842583697916055,
|
|
||||||
0.006965146979162284,
|
|
||||||
0.0040435869791615175,
|
|
||||||
0.0007104669791608842,
|
|
||||||
-0.0015763130208377163,
|
|
||||||
-0.006936193020838033,
|
|
||||||
-0.016475303020840215,
|
|
||||||
-0.028748483020837767,
|
|
||||||
-0.039618433020837784,
|
|
||||||
-0.051112303020840244,
|
|
||||||
-0.06468462302083822,
|
|
||||||
-0.07868024302083754,
|
|
||||||
-0.09101254302083817,
|
|
||||||
-0.10103437302083762,
|
|
||||||
-0.11041488302083735,
|
|
||||||
-0.11916081302083725,
|
|
||||||
-0.12789859302083784,
|
|
||||||
-0.1353792530208402,
|
|
||||||
-0.14160178302083892,
|
|
||||||
-0.1455411330208385,
|
|
||||||
-0.1484450830208388,
|
|
||||||
-0.14823350302084037,
|
|
||||||
-0.14591937302083835,
|
|
||||||
-0.1409032730208395,
|
|
||||||
-0.13525493302083902,
|
|
||||||
-0.1279646530208396,
|
|
||||||
-0.11963431302083904,
|
|
||||||
-0.11089282302084058,
|
|
||||||
-0.1027863830208382,
|
|
||||||
-0.09717347302083823,
|
|
||||||
-0.09343261302083761,
|
|
||||||
-0.0913487130208388,
|
|
||||||
-0.08906007302083907,
|
|
||||||
-0.0865687230208394,
|
|
||||||
-0.08407607302083875,
|
|
||||||
-0.07844600302084004,
|
|
||||||
-0.06968090302083851,
|
|
||||||
-0.05947139302083926,
|
|
||||||
-0.05095282302083959,
|
|
||||||
-0.042428283020839785,
|
|
||||||
-0.03218106302083967,
|
|
||||||
-0.01819858302084043,
|
|
||||||
-0.0021726530208390216,
|
|
||||||
0.01393231697916164,
|
|
||||||
0.028098946979159933,
|
|
||||||
0.040326236979161934,
|
|
||||||
0.05257029697916238,
|
|
||||||
0.06479749697916048,
|
|
||||||
0.07704745697916238
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,21 @@
|
|||||||
{ "Edfa":[{
|
{ "Edfa":[{
|
||||||
"type_variety": "high_detail_model_example",
|
"type_variety": "high_detail_model_example",
|
||||||
|
"type_def": "advanced_model",
|
||||||
"gain_flatmax": 25,
|
"gain_flatmax": 25,
|
||||||
"gain_min": 15,
|
"gain_min": 15,
|
||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||||
"out_voa_auto": false,
|
"out_voa_auto": false,
|
||||||
"allowed_for_design": false
|
"allowed_for_design": false
|
||||||
|
}, {
|
||||||
|
"type_variety": "Juniper_BoosterHG",
|
||||||
|
"type_def": "advanced_model",
|
||||||
|
"gain_flatmax": 25,
|
||||||
|
"gain_min": 10,
|
||||||
|
"p_max": 21,
|
||||||
|
"advanced_config_from_json": "Juniper-BoosterHG.json",
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type_variety": "operator_model_example",
|
"type_variety": "operator_model_example",
|
||||||
@@ -37,6 +47,17 @@
|
|||||||
"allowed_for_design": false
|
"allowed_for_design": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"type_variety": "std_high_gain",
|
||||||
|
"type_def": "variable_gain",
|
||||||
|
"gain_flatmax": 35,
|
||||||
|
"gain_min": 25,
|
||||||
|
"p_max": 21,
|
||||||
|
"nf_min": 5.5,
|
||||||
|
"nf_max": 7,
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": true
|
||||||
|
},
|
||||||
|
{
|
||||||
"type_variety": "std_medium_gain",
|
"type_variety": "std_medium_gain",
|
||||||
"type_def": "variable_gain",
|
"type_def": "variable_gain",
|
||||||
"gain_flatmax": 26,
|
"gain_flatmax": 26,
|
||||||
@@ -59,6 +80,17 @@
|
|||||||
"allowed_for_design": true
|
"allowed_for_design": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"type_variety": "high_power",
|
||||||
|
"type_def": "variable_gain",
|
||||||
|
"gain_flatmax": 16,
|
||||||
|
"gain_min": 8,
|
||||||
|
"p_max": 25,
|
||||||
|
"nf_min": 9,
|
||||||
|
"nf_max": 15,
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": false
|
||||||
|
},
|
||||||
|
{
|
||||||
"type_variety": "std_fixed_gain",
|
"type_variety": "std_fixed_gain",
|
||||||
"type_def": "fixed_gain",
|
"type_def": "fixed_gain",
|
||||||
"gain_flatmax": 21,
|
"gain_flatmax": 21,
|
||||||
@@ -66,6 +98,49 @@
|
|||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"nf0": 5.5,
|
"nf0": 5.5,
|
||||||
"allowed_for_design": false
|
"allowed_for_design": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type_variety": "4pumps_raman",
|
||||||
|
"type_def": "fixed_gain",
|
||||||
|
"gain_flatmax": 12,
|
||||||
|
"gain_min": 12,
|
||||||
|
"p_max": 21,
|
||||||
|
"nf0": -1,
|
||||||
|
"allowed_for_design": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type_variety": "hybrid_4pumps_lowgain",
|
||||||
|
"type_def": "dual_stage",
|
||||||
|
"raman": true,
|
||||||
|
"gain_min": 25,
|
||||||
|
"preamp_variety": "4pumps_raman",
|
||||||
|
"booster_variety": "std_low_gain",
|
||||||
|
"allowed_for_design": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type_variety": "hybrid_4pumps_mediumgain",
|
||||||
|
"type_def": "dual_stage",
|
||||||
|
"raman": true,
|
||||||
|
"gain_min": 25,
|
||||||
|
"preamp_variety": "4pumps_raman",
|
||||||
|
"booster_variety": "std_medium_gain",
|
||||||
|
"allowed_for_design": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type_variety": "medium+low_gain",
|
||||||
|
"type_def": "dual_stage",
|
||||||
|
"gain_min": 25,
|
||||||
|
"preamp_variety": "std_medium_gain",
|
||||||
|
"booster_variety": "std_low_gain",
|
||||||
|
"allowed_for_design": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type_variety": "medium+high_power",
|
||||||
|
"type_def": "dual_stage",
|
||||||
|
"gain_min": 25,
|
||||||
|
"preamp_variety": "std_medium_gain",
|
||||||
|
"booster_variety": "high_power",
|
||||||
|
"allowed_for_design": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Fiber":[{
|
"Fiber":[{
|
||||||
@@ -84,9 +159,41 @@
|
|||||||
"gamma": 0.000843
|
"gamma": 0.000843
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Spans":[{
|
"RamanFiber":[{
|
||||||
|
"type_variety": "SSMF",
|
||||||
|
"dispersion": 1.67e-05,
|
||||||
|
"gamma": 0.00127,
|
||||||
|
"raman_efficiency": {
|
||||||
|
"cr":[
|
||||||
|
0, 9.4E-06, 2.92E-05, 4.88E-05, 6.82E-05, 8.31E-05, 9.4E-05, 0.0001014, 0.0001069, 0.0001119,
|
||||||
|
0.0001217, 0.0001268, 0.0001365, 0.000149, 0.000165, 0.000181, 0.0001977, 0.0002192, 0.0002469,
|
||||||
|
0.0002749, 0.0002999, 0.0003206, 0.0003405, 0.0003592, 0.000374, 0.0003826, 0.0003841, 0.0003826,
|
||||||
|
0.0003802, 0.0003756, 0.0003549, 0.0003795, 0.000344, 0.0002933, 0.0002024, 0.0001158, 8.46E-05,
|
||||||
|
7.14E-05, 6.86E-05, 8.5E-05, 8.93E-05, 9.01E-05, 8.15E-05, 6.67E-05, 4.37E-05, 3.28E-05, 2.96E-05,
|
||||||
|
2.65E-05, 2.57E-05, 2.81E-05, 3.08E-05, 3.67E-05, 5.85E-05, 6.63E-05, 6.36E-05, 5.5E-05, 4.06E-05,
|
||||||
|
2.77E-05, 2.42E-05, 1.87E-05, 1.6E-05, 1.4E-05, 1.13E-05, 1.05E-05, 9.8E-06, 9.8E-06, 1.13E-05,
|
||||||
|
1.64E-05, 1.95E-05, 2.38E-05, 2.26E-05, 2.03E-05, 1.48E-05, 1.09E-05, 9.8E-06, 1.05E-05, 1.17E-05,
|
||||||
|
1.25E-05, 1.21E-05, 1.09E-05, 9.8E-06, 8.2E-06, 6.6E-06, 4.7E-06, 2.7E-06, 1.9E-06, 1.2E-06, 4E-07,
|
||||||
|
2E-07, 1E-07
|
||||||
|
],
|
||||||
|
"frequency_offset":[
|
||||||
|
0, 0.5e12, 1e12, 1.5e12, 2e12, 2.5e12, 3e12, 3.5e12, 4e12, 4.5e12, 5e12, 5.5e12, 6e12, 6.5e12, 7e12,
|
||||||
|
7.5e12, 8e12, 8.5e12, 9e12, 9.5e12, 10e12, 10.5e12, 11e12, 11.5e12, 12e12, 12.5e12, 12.75e12,
|
||||||
|
13e12, 13.25e12, 13.5e12, 14e12, 14.5e12, 14.75e12, 15e12, 15.5e12, 16e12, 16.5e12, 17e12,
|
||||||
|
17.5e12, 18e12, 18.25e12, 18.5e12, 18.75e12, 19e12, 19.5e12, 20e12, 20.5e12, 21e12, 21.5e12,
|
||||||
|
22e12, 22.5e12, 23e12, 23.5e12, 24e12, 24.5e12, 25e12, 25.5e12, 26e12, 26.5e12, 27e12, 27.5e12, 28e12,
|
||||||
|
28.5e12, 29e12, 29.5e12, 30e12, 30.5e12, 31e12, 31.5e12, 32e12, 32.5e12, 33e12, 33.5e12, 34e12, 34.5e12,
|
||||||
|
35e12, 35.5e12, 36e12, 36.5e12, 37e12, 37.5e12, 38e12, 38.5e12, 39e12, 39.5e12, 40e12, 40.5e12, 41e12,
|
||||||
|
41.5e12, 42e12
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Span":[{
|
||||||
"power_mode":true,
|
"power_mode":true,
|
||||||
"delta_power_range_db": [0,0,0.5],
|
"delta_power_range_db": [-2,3,0.5],
|
||||||
|
"max_fiber_lineic_loss_for_raman": 0.25,
|
||||||
|
"target_extended_gain": 2.5,
|
||||||
"max_length": 150,
|
"max_length": 150,
|
||||||
"length_units": "km",
|
"length_units": "km",
|
||||||
"max_loss": 28,
|
"max_loss": 28,
|
||||||
@@ -96,10 +203,13 @@
|
|||||||
"con_out": 0
|
"con_out": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Roadms":[{
|
"Roadm":[{
|
||||||
"gain_mode_default_loss": 20,
|
"target_pch_out_db": -20,
|
||||||
"power_mode_pout_target": -20,
|
"add_drop_osnr": 38,
|
||||||
"add_drop_osnr": 38
|
"restrictions": {
|
||||||
|
"preamp_variety_list":[],
|
||||||
|
"booster_variety_list":[]
|
||||||
|
}
|
||||||
}],
|
}],
|
||||||
"SI":[{
|
"SI":[{
|
||||||
"f_min": 191.3e12,
|
"f_min": 191.3e12,
|
||||||
@@ -107,10 +217,10 @@
|
|||||||
"f_max":195.1e12,
|
"f_max":195.1e12,
|
||||||
"spacing": 50e9,
|
"spacing": 50e9,
|
||||||
"power_dbm": 0,
|
"power_dbm": 0,
|
||||||
"power_range_db": [0,0,0.5],
|
"power_range_db": [0,0,1],
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 40,
|
"tx_osnr": 40,
|
||||||
"sys_margins": 0
|
"sys_margins": 2
|
||||||
}],
|
}],
|
||||||
"Transceiver":[
|
"Transceiver":[
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
@@ -623,31 +623,469 @@
|
|||||||
"con_in": null,
|
"con_in": null,
|
||||||
"con_out": null
|
"con_out": null
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lannion_CAS to Corlay",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Corlay to Loudeac",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Corlay",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Loudeac to Lorient_KMA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Loudeac",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 2.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lannion_CAS to Stbrieuc",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Stbrieuc to Rennes_STA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Stbrieuc",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 1.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lannion_CAS to Morlaix",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lorient_KMA to Loudeac",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lorient_KMA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 3.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Vannes_KBE to Lorient_KMA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Vannes_KBE",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 4.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Rennes_STA to Stbrieuc",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Rennes_STA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 0.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Brest_KLA to Morlaix",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Brest_KLA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 4.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lannion_CAS to Corlay",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Corlay to Loudeac",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Corlay",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Loudeac to Lorient_KMA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Loudeac",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 2.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lorient_KMA to Vannes_KBE",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lorient_KMA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 3.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lannion_CAS to Stbrieuc",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Stbrieuc to Rennes_STA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Stbrieuc",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 1.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lannion_CAS to Morlaix",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lorient_KMA to Loudeac",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lorient_KMA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 3.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Vannes_KBE to Lorient_KMA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Vannes_KBE",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 4.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Rennes_STA to Stbrieuc",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Rennes_STA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 0.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Brest_KLA to Morlaix",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Brest_KLA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 4.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lorient_KMA to Vannes_KBE",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lorient_KMA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 3.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Fused",
|
||||||
|
"params": {
|
||||||
|
"loss": 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lannion_CAS",
|
"from_node": "roadm Lannion_CAS",
|
||||||
|
"to_node": "east edfa in Lannion_CAS to Corlay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lannion_CAS to Corlay",
|
||||||
"to_node": "fiber (Lannion_CAS → Corlay)-F061"
|
"to_node": "fiber (Lannion_CAS → Corlay)-F061"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Corlay → Lannion_CAS)-F061",
|
"from_node": "fiber (Corlay → Lannion_CAS)-F061",
|
||||||
|
"to_node": "west edfa in Lannion_CAS to Corlay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lannion_CAS to Corlay",
|
||||||
"to_node": "roadm Lannion_CAS"
|
"to_node": "roadm Lannion_CAS"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lannion_CAS",
|
"from_node": "roadm Lannion_CAS",
|
||||||
|
"to_node": "east edfa in Lannion_CAS to Stbrieuc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lannion_CAS to Stbrieuc",
|
||||||
"to_node": "fiber (Lannion_CAS → Stbrieuc)-F056"
|
"to_node": "fiber (Lannion_CAS → Stbrieuc)-F056"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Stbrieuc → Lannion_CAS)-F056",
|
"from_node": "fiber (Stbrieuc → Lannion_CAS)-F056",
|
||||||
|
"to_node": "west edfa in Lannion_CAS to Stbrieuc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lannion_CAS to Stbrieuc",
|
||||||
"to_node": "roadm Lannion_CAS"
|
"to_node": "roadm Lannion_CAS"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lannion_CAS",
|
"from_node": "roadm Lannion_CAS",
|
||||||
|
"to_node": "east edfa in Lannion_CAS to Morlaix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lannion_CAS to Morlaix",
|
||||||
"to_node": "fiber (Lannion_CAS → Morlaix)-F059"
|
"to_node": "fiber (Lannion_CAS → Morlaix)-F059"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Morlaix → Lannion_CAS)-F059",
|
"from_node": "fiber (Morlaix → Lannion_CAS)-F059",
|
||||||
|
"to_node": "west edfa in Lannion_CAS to Morlaix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lannion_CAS to Morlaix",
|
||||||
"to_node": "roadm Lannion_CAS"
|
"to_node": "roadm Lannion_CAS"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -684,18 +1122,34 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lorient_KMA",
|
"from_node": "roadm Lorient_KMA",
|
||||||
|
"to_node": "east edfa in Lorient_KMA to Loudeac"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lorient_KMA to Loudeac",
|
||||||
"to_node": "fiber (Lorient_KMA → Loudeac)-F054"
|
"to_node": "fiber (Lorient_KMA → Loudeac)-F054"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Loudeac → Lorient_KMA)-F054",
|
"from_node": "fiber (Loudeac → Lorient_KMA)-F054",
|
||||||
|
"to_node": "west edfa in Lorient_KMA to Loudeac"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lorient_KMA to Loudeac",
|
||||||
"to_node": "roadm Lorient_KMA"
|
"to_node": "roadm Lorient_KMA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lorient_KMA",
|
"from_node": "roadm Lorient_KMA",
|
||||||
|
"to_node": "east edfa in Lorient_KMA to Vannes_KBE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lorient_KMA to Vannes_KBE",
|
||||||
"to_node": "fiber (Lorient_KMA → Vannes_KBE)-F055"
|
"to_node": "fiber (Lorient_KMA → Vannes_KBE)-F055"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Vannes_KBE → Lorient_KMA)-F055",
|
"from_node": "fiber (Vannes_KBE → Lorient_KMA)-F055",
|
||||||
|
"to_node": "west edfa in Lorient_KMA to Vannes_KBE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lorient_KMA to Vannes_KBE",
|
||||||
"to_node": "roadm Lorient_KMA"
|
"to_node": "roadm Lorient_KMA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -708,10 +1162,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Vannes_KBE",
|
"from_node": "roadm Vannes_KBE",
|
||||||
|
"to_node": "east edfa in Vannes_KBE to Lorient_KMA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Vannes_KBE to Lorient_KMA",
|
||||||
"to_node": "fiber (Vannes_KBE → Lorient_KMA)-F055"
|
"to_node": "fiber (Vannes_KBE → Lorient_KMA)-F055"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Lorient_KMA → Vannes_KBE)-F055",
|
"from_node": "fiber (Lorient_KMA → Vannes_KBE)-F055",
|
||||||
|
"to_node": "west edfa in Vannes_KBE to Lorient_KMA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Vannes_KBE to Lorient_KMA",
|
||||||
"to_node": "roadm Vannes_KBE"
|
"to_node": "roadm Vannes_KBE"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -724,18 +1186,34 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Lannion_CAS → Stbrieuc)-F056",
|
"from_node": "fiber (Lannion_CAS → Stbrieuc)-F056",
|
||||||
|
"to_node": "east edfa in Stbrieuc to Rennes_STA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Stbrieuc to Rennes_STA",
|
||||||
"to_node": "fiber (Stbrieuc → Rennes_STA)-F057"
|
"to_node": "fiber (Stbrieuc → Rennes_STA)-F057"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Rennes_STA → Stbrieuc)-F057",
|
"from_node": "fiber (Rennes_STA → Stbrieuc)-F057",
|
||||||
|
"to_node": "west edfa in Stbrieuc to Rennes_STA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Stbrieuc to Rennes_STA",
|
||||||
"to_node": "fiber (Stbrieuc → Lannion_CAS)-F056"
|
"to_node": "fiber (Stbrieuc → Lannion_CAS)-F056"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Rennes_STA",
|
"from_node": "roadm Rennes_STA",
|
||||||
|
"to_node": "east edfa in Rennes_STA to Stbrieuc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Rennes_STA to Stbrieuc",
|
||||||
"to_node": "fiber (Rennes_STA → Stbrieuc)-F057"
|
"to_node": "fiber (Rennes_STA → Stbrieuc)-F057"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Stbrieuc → Rennes_STA)-F057",
|
"from_node": "fiber (Stbrieuc → Rennes_STA)-F057",
|
||||||
|
"to_node": "west edfa in Rennes_STA to Stbrieuc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Rennes_STA to Stbrieuc",
|
||||||
"to_node": "roadm Rennes_STA"
|
"to_node": "roadm Rennes_STA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -764,10 +1242,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Brest_KLA",
|
"from_node": "roadm Brest_KLA",
|
||||||
|
"to_node": "east edfa in Brest_KLA to Morlaix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Brest_KLA to Morlaix",
|
||||||
"to_node": "fiber (Brest_KLA → Morlaix)-F060"
|
"to_node": "fiber (Brest_KLA → Morlaix)-F060"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Morlaix → Brest_KLA)-F060",
|
"from_node": "fiber (Morlaix → Brest_KLA)-F060",
|
||||||
|
"to_node": "west edfa in Brest_KLA to Morlaix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Brest_KLA to Morlaix",
|
||||||
"to_node": "roadm Brest_KLA"
|
"to_node": "roadm Brest_KLA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
@@ -2,10 +2,11 @@
|
|||||||
"path-request": [
|
"path-request": [
|
||||||
{
|
{
|
||||||
"request-id": "0",
|
"request-id": "0",
|
||||||
"source": "Lorient_KMA",
|
"source": "trx Lorient_KMA",
|
||||||
"destination": "Vannes_KBE",
|
"destination": "trx Vannes_KBE",
|
||||||
"src-tp-id": "trx Lorient_KMA",
|
"src-tp-id": "trx Lorient_KMA",
|
||||||
"dst-tp-id": "trx Vannes_KBE",
|
"dst-tp-id": "trx Vannes_KBE",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -13,8 +14,8 @@
|
|||||||
"trx_mode": null,
|
"trx_mode": null,
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"N": "null",
|
||||||
"m": "null"
|
"M": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 50000000000.0,
|
"spacing": 50000000000.0,
|
||||||
@@ -22,17 +23,15 @@
|
|||||||
"output-power": 0.0012589254117941673,
|
"output-power": 0.0012589254117941673,
|
||||||
"path_bandwidth": 100000000000.0
|
"path_bandwidth": 100000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "1",
|
"request-id": "1",
|
||||||
"source": "Brest_KLA",
|
"source": "trx Brest_KLA",
|
||||||
"destination": "Vannes_KBE",
|
"destination": "trx Vannes_KBE",
|
||||||
"src-tp-id": "trx Brest_KLA",
|
"src-tp-id": "trx Brest_KLA",
|
||||||
"dst-tp-id": "trx Vannes_KBE",
|
"dst-tp-id": "trx Vannes_KBE",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -40,8 +39,8 @@
|
|||||||
"trx_mode": "mode 1",
|
"trx_mode": "mode 1",
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"N": "null",
|
||||||
"m": "null"
|
"M": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 50000000000.0,
|
"spacing": 50000000000.0,
|
||||||
@@ -50,66 +49,42 @@
|
|||||||
"path_bandwidth": 200000000000.0
|
"path_bandwidth": 200000000000.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimizations": {
|
"explicit-route-objects": {
|
||||||
"explicit-route-include-objects": [
|
"route-object-include-exclude": [
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm Brest_KLA",
|
"node-id": "roadm Brest_KLA",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 1,
|
"index": 1,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm Lannion_CAS",
|
"node-id": "roadm Lannion_CAS",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 2,
|
"index": 2,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm Lorient_KMA",
|
"node-id": "roadm Lorient_KMA",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 3,
|
"index": 3,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm Vannes_KBE",
|
"node-id": "roadm Vannes_KBE",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -117,10 +92,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "3",
|
"request-id": "3",
|
||||||
"source": "Lannion_CAS",
|
"source": "trx Lannion_CAS",
|
||||||
"destination": "Rennes_STA",
|
"destination": "trx Rennes_STA",
|
||||||
"src-tp-id": "trx Lannion_CAS",
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
"dst-tp-id": "trx Rennes_STA",
|
"dst-tp-id": "trx Rennes_STA",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -128,8 +104,8 @@
|
|||||||
"trx_mode": "mode 1",
|
"trx_mode": "mode 1",
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"N": "null",
|
||||||
"m": "null"
|
"M": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 50000000000.0,
|
"spacing": 50000000000.0,
|
||||||
@@ -137,17 +113,15 @@
|
|||||||
"output-power": null,
|
"output-power": null,
|
||||||
"path_bandwidth": 60000000000.0
|
"path_bandwidth": 60000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "4",
|
"request-id": "4",
|
||||||
"source": "Rennes_STA",
|
"source": "trx Rennes_STA",
|
||||||
"destination": "Lannion_CAS",
|
"destination": "trx Lannion_CAS",
|
||||||
"src-tp-id": "trx Rennes_STA",
|
"src-tp-id": "trx Rennes_STA",
|
||||||
"dst-tp-id": "trx Lannion_CAS",
|
"dst-tp-id": "trx Lannion_CAS",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -155,8 +129,8 @@
|
|||||||
"trx_mode": null,
|
"trx_mode": null,
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"N": "null",
|
||||||
"m": "null"
|
"M": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 75000000000.0,
|
"spacing": 75000000000.0,
|
||||||
@@ -164,17 +138,15 @@
|
|||||||
"output-power": 0.0019952623149688794,
|
"output-power": 0.0019952623149688794,
|
||||||
"path_bandwidth": 150000000000.0
|
"path_bandwidth": 150000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "5",
|
"request-id": "5",
|
||||||
"source": "Rennes_STA",
|
"source": "trx Rennes_STA",
|
||||||
"destination": "Lannion_CAS",
|
"destination": "trx Lannion_CAS",
|
||||||
"src-tp-id": "trx Rennes_STA",
|
"src-tp-id": "trx Rennes_STA",
|
||||||
"dst-tp-id": "trx Lannion_CAS",
|
"dst-tp-id": "trx Lannion_CAS",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -182,8 +154,8 @@
|
|||||||
"trx_mode": "mode 2",
|
"trx_mode": "mode 2",
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"N": "null",
|
||||||
"m": "null"
|
"M": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 75000000000.0,
|
"spacing": 75000000000.0,
|
||||||
@@ -191,17 +163,15 @@
|
|||||||
"output-power": 0.0019952623149688794,
|
"output-power": 0.0019952623149688794,
|
||||||
"path_bandwidth": 20000000000.0
|
"path_bandwidth": 20000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "6",
|
"request-id": "6",
|
||||||
"source": "Lannion_CAS",
|
"source": "trx Lannion_CAS",
|
||||||
"destination": "Lorient_KMA",
|
"destination": "trx Lorient_KMA",
|
||||||
"src-tp-id": "trx Lannion_CAS",
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
"dst-tp-id": "trx Lorient_KMA",
|
"dst-tp-id": "trx Lorient_KMA",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -209,8 +179,8 @@
|
|||||||
"trx_mode": "mode 1",
|
"trx_mode": "mode 1",
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"N": "null",
|
||||||
"m": "null"
|
"M": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 50000000000.0,
|
"spacing": 50000000000.0,
|
||||||
@@ -218,17 +188,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "7",
|
"request-id": "7",
|
||||||
"source": "Lannion_CAS",
|
"source": "trx Lannion_CAS",
|
||||||
"destination": "Lorient_KMA",
|
"destination": "trx Lorient_KMA",
|
||||||
"src-tp-id": "trx Lannion_CAS",
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
"dst-tp-id": "trx Lorient_KMA",
|
"dst-tp-id": "trx Lorient_KMA",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -236,8 +204,8 @@
|
|||||||
"trx_mode": "mode 1",
|
"trx_mode": "mode 1",
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"N": "null",
|
||||||
"m": "null"
|
"M": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 50000000000.0,
|
"spacing": 50000000000.0,
|
||||||
@@ -245,17 +213,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 400000000000.0
|
"path_bandwidth": 400000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "7b",
|
"request-id": "7b",
|
||||||
"source": "Lannion_CAS",
|
"source": "trx Lannion_CAS",
|
||||||
"destination": "Lorient_KMA",
|
"destination": "trx Lorient_KMA",
|
||||||
"src-tp-id": "trx Lannion_CAS",
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
"dst-tp-id": "trx Lorient_KMA",
|
"dst-tp-id": "trx Lorient_KMA",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -263,8 +229,8 @@
|
|||||||
"trx_mode": "mode 1",
|
"trx_mode": "mode 1",
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"N": "null",
|
||||||
"m": "null"
|
"M": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 75000000000.0,
|
"spacing": 75000000000.0,
|
||||||
@@ -272,9 +238,6 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 400000000000.0
|
"path_bandwidth": 400000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -282,9 +245,8 @@
|
|||||||
{
|
{
|
||||||
"synchronization-id": "3",
|
"synchronization-id": "3",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "false",
|
||||||
"link-diverse": "True",
|
"disjointness": "node link",
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
"3",
|
"3",
|
||||||
"1"
|
"1"
|
||||||
@@ -294,9 +256,8 @@
|
|||||||
{
|
{
|
||||||
"synchronization-id": "4",
|
"synchronization-id": "4",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "false",
|
||||||
"link-diverse": "True",
|
"disjointness": "node link",
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
"4",
|
"4",
|
||||||
"5"
|
"5"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -18,52 +18,78 @@ from pathlib import Path
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from logging import getLogger, basicConfig, CRITICAL, DEBUG, INFO
|
from logging import getLogger, basicConfig, CRITICAL, DEBUG, INFO
|
||||||
from json import dumps, loads
|
from json import dumps, loads
|
||||||
from networkx import (draw_networkx_nodes, draw_networkx_edges,
|
|
||||||
draw_networkx_labels)
|
|
||||||
from numpy import mean
|
from numpy import mean
|
||||||
from gnpy.core.service_sheet import convert_service_sheet, Request_element, Element
|
from gnpy.core.service_sheet import convert_service_sheet, Request_element, Element
|
||||||
from gnpy.core.utils import load_json
|
from gnpy.core.utils import load_json
|
||||||
from gnpy.core.network import load_network, build_network, set_roadm_loss, 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, automatic_spacing
|
from gnpy.core.equipment import load_equipment, trx_mode_params, automatic_nch
|
||||||
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fused, Fiber
|
from gnpy.core.elements import Transceiver, Roadm
|
||||||
from gnpy.core.utils import db2lin, lin2db
|
from gnpy.core.utils import db2lin, lin2db
|
||||||
from gnpy.core.request import (Path_request, Result_element, compute_constrained_path,
|
from gnpy.core.request import (Path_request, Result_element,
|
||||||
propagate, jsontocsv, Disjunction, compute_path_dsjctn, requests_aggregation,
|
propagate, jsontocsv, Disjunction, compute_path_dsjctn,
|
||||||
propagate_and_optimize_mode)
|
requests_aggregation, propagate_and_optimize_mode,
|
||||||
|
BLOCKING_NOPATH, BLOCKING_NOMODE,
|
||||||
|
find_reversed_path)
|
||||||
|
from gnpy.core.exceptions import (ConfigurationError, EquipmentConfigError, NetworkTopologyError,
|
||||||
|
ServiceError, DisjunctionError)
|
||||||
|
import gnpy.core.ansi_escapes as ansi_escapes
|
||||||
|
from gnpy.core.spectrum_assignment import (build_oms_list, pth_assign_spectrum)
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from math import ceil
|
from math import ceil
|
||||||
import time
|
|
||||||
|
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'
|
#EQPT_LIBRARY_FILENAME = Path(__file__).parent / 'eqpt_config.json'
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
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 = ArgumentParser(description='A function that computes performances for a list of ' +
|
||||||
parser.add_argument('network_filename', nargs='?', type = Path, default= Path(__file__).parent / 'meshTopologyExampleV2.xls')
|
'services provided in a json file or an excel sheet.')
|
||||||
parser.add_argument('service_filename', nargs='?', type = Path, default= Path(__file__).parent / 'meshTopologyExampleV2.xls')
|
PARSER.add_argument('network_filename', nargs='?', type=Path,\
|
||||||
parser.add_argument('eqpt_filename', nargs='?', type = Path, default=Path(__file__).parent / 'eqpt_config.json')
|
default=Path(__file__).parent / 'meshTopologyExampleV2.xls',\
|
||||||
parser.add_argument('-v', '--verbose', action='count', default=0, help='increases verbosity for each occurence')
|
help='input topology file in xls or json')
|
||||||
parser.add_argument('-o', '--output', type = Path)
|
PARSER.add_argument('service_filename', nargs='?', type=Path,\
|
||||||
|
default=Path(__file__).parent / 'meshTopologyExampleV2.xls',\
|
||||||
|
help='input service file in xls or json')
|
||||||
|
PARSER.add_argument('eqpt_filename', nargs='?', type=Path,\
|
||||||
|
default=Path(__file__).parent / 'eqpt_config.json',\
|
||||||
|
help='input equipment library in json. Default is eqpt_config.json')
|
||||||
|
PARSER.add_argument('-bi', '--bidir', action='store_true',\
|
||||||
|
help='considers that all demands are bidir')
|
||||||
|
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):
|
def requests_from_json(json_data, equipment):
|
||||||
|
""" converts the json data into a list of requests elements
|
||||||
|
"""
|
||||||
requests_list = []
|
requests_list = []
|
||||||
|
|
||||||
for req in json_data['path-request']:
|
for req in json_data['path-request']:
|
||||||
# init all params from request
|
# init all params from request
|
||||||
params = {}
|
params = {}
|
||||||
params['request_id'] = req['request-id']
|
params['request_id'] = req['request-id']
|
||||||
params['source'] = req['src-tp-id']
|
params['source'] = req['source']
|
||||||
params['destination'] = req['dst-tp-id']
|
params['bidir'] = req['bidirectional']
|
||||||
|
params['destination'] = req['destination']
|
||||||
params['trx_type'] = req['path-constraints']['te-bandwidth']['trx_type']
|
params['trx_type'] = req['path-constraints']['te-bandwidth']['trx_type']
|
||||||
params['trx_mode'] = req['path-constraints']['te-bandwidth']['trx_mode']
|
params['trx_mode'] = req['path-constraints']['te-bandwidth']['trx_mode']
|
||||||
params['format'] = params['trx_mode']
|
params['format'] = params['trx_mode']
|
||||||
nd_list = req['optimizations']['explicit-route-include-objects']
|
|
||||||
params['nodes_list'] = [n['unnumbered-hop']['node-id'] for n in nd_list]
|
|
||||||
params['loose_list'] = [n['unnumbered-hop']['hop-type'] for n in nd_list]
|
|
||||||
params['spacing'] = req['path-constraints']['te-bandwidth']['spacing']
|
params['spacing'] = req['path-constraints']['te-bandwidth']['spacing']
|
||||||
|
try:
|
||||||
|
nd_list = req['explicit-route-objects']['route-object-include-exclude']
|
||||||
|
except KeyError:
|
||||||
|
nd_list = []
|
||||||
|
params['nodes_list'] = [n['num-unnum-hop']['node-id'] for n in nd_list]
|
||||||
|
params['loose_list'] = [n['num-unnum-hop']['hop-type'] for n in nd_list]
|
||||||
# recover trx physical param (baudrate, ...) from type and mode
|
# recover trx physical param (baudrate, ...) from type and mode
|
||||||
# in trx_mode_params optical power is read from equipment['SI']['default'] and
|
# in trx_mode_params optical power is read from equipment['SI']['default'] and
|
||||||
# nb_channel is computed based on min max frequency and spacing
|
# nb_channel is computed based on min max frequency and spacing
|
||||||
@@ -72,12 +98,15 @@ def requests_from_json(json_data,equipment):
|
|||||||
# print(trx_params['min_spacing'])
|
# print(trx_params['min_spacing'])
|
||||||
# optical power might be set differently in the request. if it is indicated then the
|
# optical power might be set differently in the request. if it is indicated then the
|
||||||
# params['power'] is updated
|
# params['power'] is updated
|
||||||
|
try:
|
||||||
if req['path-constraints']['te-bandwidth']['output-power']:
|
if req['path-constraints']['te-bandwidth']['output-power']:
|
||||||
params['power'] = req['path-constraints']['te-bandwidth']['output-power']
|
params['power'] = req['path-constraints']['te-bandwidth']['output-power']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
# same process for nb-channel
|
# same process for nb-channel
|
||||||
f_min = params['f_min']
|
f_min = params['f_min']
|
||||||
f_max_from_si = params['f_max']
|
f_max_from_si = params['f_max']
|
||||||
|
try:
|
||||||
if req['path-constraints']['te-bandwidth']['max-nb-of-channel'] is not None:
|
if req['path-constraints']['te-bandwidth']['max-nb-of-channel'] is not None:
|
||||||
nch = req['path-constraints']['te-bandwidth']['max-nb-of-channel']
|
nch = req['path-constraints']['te-bandwidth']['max-nb-of-channel']
|
||||||
params['nb_channel'] = nch
|
params['nb_channel'] = nch
|
||||||
@@ -85,7 +114,8 @@ def requests_from_json(json_data,equipment):
|
|||||||
params['f_max'] = f_min + nch*spacing
|
params['f_max'] = f_min + nch*spacing
|
||||||
else:
|
else:
|
||||||
params['nb_channel'] = automatic_nch(f_min, f_max_from_si, params['spacing'])
|
params['nb_channel'] = automatic_nch(f_min, f_max_from_si, params['spacing'])
|
||||||
|
except KeyError:
|
||||||
|
params['nb_channel'] = automatic_nch(f_min, f_max_from_si, params['spacing'])
|
||||||
consistency_check(params, f_max_from_si)
|
consistency_check(params, f_max_from_si)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -96,220 +126,251 @@ def requests_from_json(json_data,equipment):
|
|||||||
return requests_list
|
return requests_list
|
||||||
|
|
||||||
def consistency_check(params, f_max_from_si):
|
def consistency_check(params, f_max_from_si):
|
||||||
|
""" checks that the requested parameters are consistant (spacing vs nb channel,
|
||||||
|
vs transponder mode...)
|
||||||
|
"""
|
||||||
f_min = params['f_min']
|
f_min = params['f_min']
|
||||||
f_max = params['f_max']
|
f_max = params['f_max']
|
||||||
max_recommanded_nb_channels = automatic_nch(f_min,f_max,
|
max_recommanded_nb_channels = automatic_nch(f_min, f_max, params['spacing'])
|
||||||
params['spacing'])
|
|
||||||
if params['baud_rate'] is not None:
|
if params['baud_rate'] is not None:
|
||||||
#implicitely means that a mode is defined with min_spacing
|
#implicitely means that a mode is defined with min_spacing
|
||||||
if params['min_spacing'] > params['spacing']:
|
if params['min_spacing'] > params['spacing']:
|
||||||
msg = f'Request {params["request_id"]} has spacing below transponder {params["trx_type"]}'+\
|
msg = f'Request {params["request_id"]} has spacing below transponder ' +\
|
||||||
f' {params["trx_mode"]} min spacing value {params["min_spacing"]*1e-9}GHz.\n'+\
|
f'{params["trx_type"]} {params["trx_mode"]} min spacing value ' +\
|
||||||
'Computation stopped'
|
f'{params["min_spacing"]*1e-9}GHz.\nComputation stopped'
|
||||||
print(msg)
|
print(msg)
|
||||||
logger.critical(msg)
|
LOGGER.critical(msg)
|
||||||
exit()
|
raise ServiceError(msg)
|
||||||
if f_max > f_max_from_si:
|
if f_max > f_max_from_si:
|
||||||
msg = dedent(f'''
|
msg = dedent(f'''
|
||||||
Requested channel number {params["nb_channel"]}, baud rate {params["baud_rate"]} GHz and requested spacing {params["spacing"]*1e-9}GHz
|
Requested channel number {params["nb_channel"]}, baud rate {params["baud_rate"]} GHz and requested spacing {params["spacing"]*1e-9}GHz
|
||||||
is not consistent with frequency range {f_min*1e-12} THz, {f_max*1e-12} THz, min recommanded spacing {params["min_spacing"]*1e-9}GHz.
|
is not consistent with frequency range {f_min*1e-12} THz, {f_max*1e-12} THz, min recommanded spacing {params["min_spacing"]*1e-9}GHz.
|
||||||
max recommanded nb of channels is {max_recommanded_nb_channels}
|
max recommanded nb of channels is {max_recommanded_nb_channels}
|
||||||
Computation stopped.''')
|
Computation stopped.''')
|
||||||
logger.critical(msg)
|
LOGGER.critical(msg)
|
||||||
exit()
|
raise ServiceError(msg)
|
||||||
|
|
||||||
|
|
||||||
def disjunctions_from_json(json_data):
|
def disjunctions_from_json(json_data):
|
||||||
|
""" reads the disjunction requests from the json dict and create the list
|
||||||
|
of requested disjunctions for this set of requests
|
||||||
|
"""
|
||||||
disjunctions_list = []
|
disjunctions_list = []
|
||||||
|
try:
|
||||||
|
temp_test = json_data['synchronization']
|
||||||
|
except KeyError:
|
||||||
|
temp_test = []
|
||||||
|
if temp_test:
|
||||||
for snc in json_data['synchronization']:
|
for snc in json_data['synchronization']:
|
||||||
params = {}
|
params = {}
|
||||||
params['disjunction_id'] = snc['synchronization-id']
|
params['disjunction_id'] = snc['synchronization-id']
|
||||||
params['relaxable'] = snc['svec']['relaxable']
|
params['relaxable'] = snc['svec']['relaxable']
|
||||||
params['link_diverse'] = snc['svec']['link-diverse']
|
params['link_diverse'] = 'link' in snc['svec']['disjointness']
|
||||||
params['node_diverse'] = snc['svec']['node-diverse']
|
params['node_diverse'] = 'node' in snc['svec']['disjointness']
|
||||||
params['disjunctions_req'] = snc['svec']['request-id-number']
|
params['disjunctions_req'] = snc['svec']['request-id-number']
|
||||||
disjunctions_list.append(Disjunction(**params))
|
disjunctions_list.append(Disjunction(**params))
|
||||||
|
|
||||||
return disjunctions_list
|
return disjunctions_list
|
||||||
|
|
||||||
|
|
||||||
def load_requests(filename,eqpt_filename):
|
def load_requests(filename, eqpt_filename, bidir):
|
||||||
|
""" loads the requests from a json or an excel file into a data string
|
||||||
|
"""
|
||||||
if filename.suffix.lower() == '.xls':
|
if filename.suffix.lower() == '.xls':
|
||||||
logger.info('Automatically converting requests from XLS to JSON')
|
LOGGER.info('Automatically converting requests from XLS to JSON')
|
||||||
json_data = convert_service_sheet(filename,eqpt_filename)
|
try:
|
||||||
|
json_data = convert_service_sheet(filename, eqpt_filename, bidir=bidir)
|
||||||
|
except ServiceError as this_e:
|
||||||
|
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}')
|
||||||
|
exit(1)
|
||||||
else:
|
else:
|
||||||
with open(filename, encoding='utf-8') as f:
|
with open(filename, encoding='utf-8') as my_f:
|
||||||
json_data = loads(f.read())
|
json_data = loads(my_f.read())
|
||||||
return json_data
|
return json_data
|
||||||
|
|
||||||
def compute_path(network, equipment, pathreqlist):
|
|
||||||
|
|
||||||
# This function is obsolete and not relevant with respect to network building: suggest either to correct
|
|
||||||
# or to suppress it
|
|
||||||
|
|
||||||
path_res_list = []
|
|
||||||
|
|
||||||
for pathreq in pathreqlist:
|
|
||||||
#need to rebuid the network for each path because the total power
|
|
||||||
#can be different and the choice of amplifiers in autodesign is power dependant
|
|
||||||
#but the design is the same if the total power is the same
|
|
||||||
#TODO parametrize the total spectrum power so the same design can be shared
|
|
||||||
p_db = lin2db(pathreq.power*1e3)
|
|
||||||
p_total_db = p_db + lin2db(pathreq.nb_channel)
|
|
||||||
build_network(network, equipment, p_db, p_total_db)
|
|
||||||
pathreq.nodes_list.append(pathreq.destination)
|
|
||||||
#we assume that the destination is a strict constraint
|
|
||||||
pathreq.loose_list.append('strict')
|
|
||||||
print(f'Computing path from {pathreq.source} to {pathreq.destination}')
|
|
||||||
print(f'with path constraint: {[pathreq.source]+pathreq.nodes_list}') #adding first node to be clearer on the output
|
|
||||||
total_path = compute_constrained_path(network, pathreq)
|
|
||||||
print(f'Computed path (roadms):{[e.uid for e in total_path if isinstance(e, Roadm)]}\n')
|
|
||||||
|
|
||||||
if total_path :
|
|
||||||
total_path = propagate(total_path,pathreq,equipment, show=False)
|
|
||||||
else:
|
|
||||||
total_path = []
|
|
||||||
# we record the last tranceiver object in order to have th whole
|
|
||||||
# information about spectrum. Important Note: since transceivers
|
|
||||||
# attached to roadms are actually logical elements to simulate
|
|
||||||
# performance, several demands having the same destination may use
|
|
||||||
# the same transponder for the performance simaulation. This is why
|
|
||||||
# we use deepcopy: to ensure each propagation is recorded and not
|
|
||||||
# overwritten
|
|
||||||
|
|
||||||
path_res_list.append(deepcopy(total_path))
|
|
||||||
return path_res_list
|
|
||||||
|
|
||||||
def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
||||||
|
""" use a list but a dictionnary might be helpful to find path based on request_id
|
||||||
# use a list but a dictionnary might be helpful to find path bathsed on request_id
|
TODO change all these req, dsjct, res lists into dict !
|
||||||
# TODO change all these req, dsjct, res lists into dict !
|
"""
|
||||||
path_res_list = []
|
path_res_list = []
|
||||||
|
reversed_path_res_list = []
|
||||||
|
propagated_reversed_path_res_list = []
|
||||||
|
|
||||||
for i, pathreq in enumerate(pathreqlist):
|
for i, pathreq in enumerate(pathreqlist):
|
||||||
|
|
||||||
# use the power specified in requests but might be different from the one specified for design
|
# use the power specified in requests but might be different from the one
|
||||||
# the power is an optional parameter for requests definition
|
# specified for design the power is an optional parameter for requests
|
||||||
# if optional, use the one defines in eqt_config.json
|
# definition if optional, use the one defines in eqt_config.json
|
||||||
p_db = lin2db(pathreq.power*1e3)
|
p_db = lin2db(pathreq.power*1e3)
|
||||||
p_total_db = p_db + lin2db(pathreq.nb_channel)
|
p_total_db = p_db + lin2db(pathreq.nb_channel)
|
||||||
print(f'request {pathreq.request_id}')
|
print(f'request {pathreq.request_id}')
|
||||||
print(f'Computing path from {pathreq.source} to {pathreq.destination}')
|
print(f'Computing path from {pathreq.source} to {pathreq.destination}')
|
||||||
print(f'with path constraint: {[pathreq.source]+pathreq.nodes_list}') #adding first node to be clearer on the output
|
# adding first node to be clearer on the output
|
||||||
|
print(f'with path constraint: {[pathreq.source] + pathreq.nodes_list}')
|
||||||
|
|
||||||
total_path = pathlist[i]
|
# pathlist[i] contains the whole path information for request i
|
||||||
print(f'Computed path (roadms):{[e.uid for e in total_path if isinstance(e, Roadm)]}\n')
|
# last element is a transciver and where the result of the propagation is
|
||||||
|
# recorded.
|
||||||
|
# Important Note: since transceivers attached to roadms are actually logical
|
||||||
|
# elements to simulate performance, several demands having the same destination
|
||||||
|
# may use the same transponder for the performance simulation. This is why
|
||||||
|
# we use deepcopy: to ensure that each propagation is recorded and not overwritten
|
||||||
|
total_path = deepcopy(pathlist[i])
|
||||||
|
print(f'Computed path (roadms):{[e.uid for e in total_path if isinstance(e, Roadm)]}')
|
||||||
# for debug
|
# for debug
|
||||||
# print(f'{pathreq.baud_rate} {pathreq.power} {pathreq.spacing} {pathreq.nb_channel}')
|
# print(f'{pathreq.baud_rate} {pathreq.power} {pathreq.spacing} {pathreq.nb_channel}')
|
||||||
if total_path:
|
if total_path:
|
||||||
if pathreq.baud_rate is not None:
|
if pathreq.baud_rate is not None:
|
||||||
total_path = propagate(total_path,pathreq,equipment, show=False)
|
# means that at this point the mode was entered/forced by user and thus a
|
||||||
|
# baud_rate was defined
|
||||||
|
total_path = propagate(total_path, pathreq, equipment)
|
||||||
temp_snr01nm = round(mean(total_path[-1].snr+lin2db(pathreq.baud_rate/(12.5e9))), 2)
|
temp_snr01nm = round(mean(total_path[-1].snr+lin2db(pathreq.baud_rate/(12.5e9))), 2)
|
||||||
if temp_snr01nm < pathreq.OSNR:
|
if temp_snr01nm < pathreq.OSNR:
|
||||||
msg = f'\tWarning! Request {pathreq.request_id} computed path from {pathreq.source} to {pathreq.destination} does not pass with {pathreq.tsp_mode}\n' +\
|
msg = f'\tWarning! Request {pathreq.request_id} computed path from' +\
|
||||||
f'\tcomputedSNR in 0.1nm = {temp_snr01nm} - required osnr {pathreq.OSNR}\n'
|
f' {pathreq.source} to {pathreq.destination} does not pass with' +\
|
||||||
|
f' {pathreq.tsp_mode}\n\tcomputedSNR in 0.1nm = {temp_snr01nm} ' +\
|
||||||
|
f'- required osnr {pathreq.OSNR}'
|
||||||
print(msg)
|
print(msg)
|
||||||
logger.warning(msg)
|
LOGGER.warning(msg)
|
||||||
total_path = []
|
pathreq.blocking_reason = 'MODE_NOT_FEASIBLE'
|
||||||
else:
|
else:
|
||||||
total_path, mode = propagate_and_optimize_mode(total_path, pathreq, equipment)
|
total_path, mode = propagate_and_optimize_mode(total_path, pathreq, equipment)
|
||||||
# if no baudrate satisfies spacing, no mode is returned and an empty path is returned
|
# if no baudrate satisfies spacing, no mode is returned and the last explored mode
|
||||||
# a warning is shown in the propagate_and_optimize_mode
|
# a warning is shown in the propagate_and_optimize_mode
|
||||||
if mode is not None :
|
|
||||||
# propagate_and_optimize_mode function returns the mode with the highest bitrate
|
# propagate_and_optimize_mode function returns the mode with the highest bitrate
|
||||||
# that passes. if no mode passes, then it returns an empty path
|
# that passes. if no mode passes, then a attribute blocking_reason is added on
|
||||||
|
# pathreq that contains the reason for blocking: 'NO_PATH', 'NO_FEASIBLE_MODE', ...
|
||||||
|
try:
|
||||||
|
if pathreq.blocking_reason in BLOCKING_NOPATH:
|
||||||
|
total_path = []
|
||||||
|
elif pathreq.blocking_reason in BLOCKING_NOMODE:
|
||||||
|
pathreq.baud_rate = mode['baud_rate']
|
||||||
|
pathreq.tsp_mode = mode['format']
|
||||||
|
pathreq.format = mode['format']
|
||||||
|
pathreq.OSNR = mode['OSNR']
|
||||||
|
pathreq.tx_osnr = mode['tx_osnr']
|
||||||
|
pathreq.bit_rate = mode['bit_rate']
|
||||||
|
# other blocking reason should not appear at this point
|
||||||
|
except AttributeError:
|
||||||
pathreq.baud_rate = mode['baud_rate']
|
pathreq.baud_rate = mode['baud_rate']
|
||||||
pathreq.tsp_mode = mode['format']
|
pathreq.tsp_mode = mode['format']
|
||||||
pathreq.format = mode['format']
|
pathreq.format = mode['format']
|
||||||
pathreq.OSNR = mode['OSNR']
|
pathreq.OSNR = mode['OSNR']
|
||||||
pathreq.tx_osnr = mode['tx_osnr']
|
pathreq.tx_osnr = mode['tx_osnr']
|
||||||
pathreq.bit_rate = mode['bit_rate']
|
pathreq.bit_rate = mode['bit_rate']
|
||||||
else :
|
|
||||||
total_path = []
|
|
||||||
# we record the last tranceiver object in order to have th whole
|
|
||||||
# information about spectrum. Important Note: since transceivers
|
|
||||||
# attached to roadms are actually logical elements to simulate
|
|
||||||
# performance, several demands having the same destination may use
|
|
||||||
# the same transponder for the performance simaulation. This is why
|
|
||||||
# we use deepcopy: to ensure each propagation is recorded and not
|
|
||||||
# overwritten
|
|
||||||
|
|
||||||
path_res_list.append(deepcopy(total_path))
|
# reversed path is needed for correct spectrum assignment
|
||||||
return path_res_list
|
reversed_path = find_reversed_path(pathlist[i])
|
||||||
|
if pathreq.bidir:
|
||||||
|
# only propagate if bidir is true, but needs the reversed path anyway for
|
||||||
|
# correct spectrum assignment
|
||||||
|
rev_p = deepcopy(reversed_path)
|
||||||
|
|
||||||
|
print(f'\n\tPropagating Z to A direction {pathreq.destination} to {pathreq.source}')
|
||||||
|
print(f'\tPath (roadsm) {[r.uid for r in rev_p if isinstance(r,Roadm)]}\n')
|
||||||
|
propagated_reversed_path = propagate(rev_p, pathreq, equipment)
|
||||||
|
temp_snr01nm = round(mean(propagated_reversed_path[-1].snr +\
|
||||||
|
lin2db(pathreq.baud_rate/(12.5e9))), 2)
|
||||||
|
if temp_snr01nm < pathreq.OSNR:
|
||||||
|
msg = f'\tWarning! Request {pathreq.request_id} computed path from' +\
|
||||||
|
f' {pathreq.source} to {pathreq.destination} does not pass with' +\
|
||||||
|
f' {pathreq.tsp_mode}\n' +\
|
||||||
|
f'\tcomputedSNR in 0.1nm = {temp_snr01nm} - required osnr {pathreq.OSNR}'
|
||||||
|
print(msg)
|
||||||
|
LOGGER.warning(msg)
|
||||||
|
# TODO selection of mode should also be on reversed direction !!
|
||||||
|
pathreq.blocking_reason = 'MODE_NOT_FEASIBLE'
|
||||||
|
else:
|
||||||
|
propagated_reversed_path = []
|
||||||
|
else:
|
||||||
|
msg = 'Total path is empty. No propagation'
|
||||||
|
print(msg)
|
||||||
|
LOGGER.info(msg)
|
||||||
|
reversed_path = []
|
||||||
|
propagated_reversed_path = []
|
||||||
|
|
||||||
|
path_res_list.append(total_path)
|
||||||
|
reversed_path_res_list.append(reversed_path)
|
||||||
|
propagated_reversed_path_res_list.append(propagated_reversed_path)
|
||||||
|
# print to have a nice output
|
||||||
|
print('')
|
||||||
|
return path_res_list, reversed_path_res_list, propagated_reversed_path_res_list
|
||||||
|
|
||||||
def correct_route_list(network, pathreqlist):
|
def correct_route_list(network, pathreqlist):
|
||||||
# prepares the format of route list of nodes to be consistant
|
""" prepares the format of route list of nodes to be consistant
|
||||||
# remove wrong names, remove endpoints
|
remove wrong names, remove endpoints
|
||||||
# also correct source and destination
|
also correct source and destination
|
||||||
anytype = [n.uid for n in network.nodes() if not isinstance(n, Transceiver) and not isinstance(n, Fiber)]
|
"""
|
||||||
# TODO there is a problem of identification of fibers in case of parallel fibers bitween two adjacent roadms
|
anytype = [n.uid for n in network.nodes()]
|
||||||
# so fiber constraint is not supported
|
# TODO there is a problem of identification of fibers in case of parallel fibers
|
||||||
|
# between two adjacent roadms so fiber constraint is not supported
|
||||||
transponders = [n.uid for n in network.nodes() if isinstance(n, Transceiver)]
|
transponders = [n.uid for n in network.nodes() if isinstance(n, Transceiver)]
|
||||||
for pathreq in pathreqlist:
|
for pathreq in pathreqlist:
|
||||||
for i, n_id in enumerate(pathreq.nodes_list):
|
for i, n_id in enumerate(pathreq.nodes_list):
|
||||||
# replace possibly wrong name with a formated roadm name
|
# replace possibly wrong name with a formated roadm name
|
||||||
# print(n_id)
|
# print(n_id)
|
||||||
if n_id not in anytype:
|
if n_id not in anytype:
|
||||||
|
# find nodes name that include constraint among all possible names except
|
||||||
|
# transponders (not yet supported as constraints).
|
||||||
nodes_suggestion = [uid for uid in anytype \
|
nodes_suggestion = [uid for uid in anytype \
|
||||||
if n_id.lower() in uid.lower()]
|
if n_id.lower() in uid.lower() and uid not in transponders]
|
||||||
if pathreq.loose_list[i] == 'loose':
|
if pathreq.loose_list[i] == 'LOOSE':
|
||||||
if len(nodes_suggestion) > 0:
|
if len(nodes_suggestion) > 0:
|
||||||
new_n = nodes_suggestion[0]
|
new_n = nodes_suggestion[0]
|
||||||
print(f'invalid route node specified:\
|
print(f'invalid route node specified:\
|
||||||
\n\'{n_id}\', replaced with \'{new_n}\'')
|
\n\'{n_id}\', replaced with \'{new_n}\'')
|
||||||
pathreq.nodes_list[i] = new_n
|
pathreq.nodes_list[i] = new_n
|
||||||
else:
|
else:
|
||||||
print(f'\x1b[1;33;40m'+f'invalid route node specified \'{n_id}\', could not use it as constraint, skipped!'+'\x1b[0m')
|
print(f'\x1b[1;33;40m'+f'invalid route node specified \'{n_id}\',' +\
|
||||||
|
f' could not use it as constraint, skipped!'+'\x1b[0m')
|
||||||
pathreq.nodes_list.remove(n_id)
|
pathreq.nodes_list.remove(n_id)
|
||||||
pathreq.loose_list.pop(i)
|
pathreq.loose_list.pop(i)
|
||||||
else:
|
else:
|
||||||
msg = f'\x1b[1;33;40m'+f'could not find node : {n_id} in network topology. Strict constraint can not be applied.'+'\x1b[0m'
|
msg = f'\x1b[1;33;40m'+f'could not find node: {n_id} in network topology.' +\
|
||||||
logger.critical(msg)
|
f' Strict constraint can not be applied.' + '\x1b[0m'
|
||||||
|
LOGGER.critical(msg)
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
if pathreq.source not in transponders:
|
if pathreq.source not in transponders:
|
||||||
msg = f'\x1b[1;31;40m'+f'Request: {pathreq.request_id}: could not find transponder source : {pathreq.source}.'+'\x1b[0m'
|
msg = f'\x1b[1;31;40m' + f'Request: {pathreq.request_id}: could not find' +\
|
||||||
logger.critical(msg)
|
f' transponder source: {pathreq.source}.'+'\x1b[0m'
|
||||||
|
LOGGER.critical(msg)
|
||||||
print(f'{msg}\nComputation stopped.')
|
print(f'{msg}\nComputation stopped.')
|
||||||
exit()
|
raise ServiceError(msg)
|
||||||
|
|
||||||
if pathreq.destination not in transponders:
|
if pathreq.destination not in transponders:
|
||||||
msg = f'\x1b[1;31;40m'+f'Request: {pathreq.request_id}: could not find transponder destination : {pathreq.destination}.'+'\x1b[0m'
|
msg = f'\x1b[1;31;40m'+f'Request: {pathreq.request_id}: could not find' +\
|
||||||
logger.critical(msg)
|
f' transponder destination: {pathreq.destination}.'+'\x1b[0m'
|
||||||
|
LOGGER.critical(msg)
|
||||||
print(f'{msg}\nComputation stopped.')
|
print(f'{msg}\nComputation stopped.')
|
||||||
exit()
|
raise ServiceError(msg)
|
||||||
|
|
||||||
# TODO remove endpoints from this list in case they were added by the user in the xls or json files
|
# TODO remove endpoints from this list in case they were added by the user
|
||||||
|
# in the xls or json files
|
||||||
return pathreqlist
|
return pathreqlist
|
||||||
|
|
||||||
def correct_disjn(disjn):
|
def correct_disjn(disjn):
|
||||||
|
""" clean disjunctions to remove possible repetition
|
||||||
|
"""
|
||||||
local_disjn = disjn.copy()
|
local_disjn = disjn.copy()
|
||||||
for el in local_disjn:
|
for elem in local_disjn:
|
||||||
for d in local_disjn:
|
for dis_elem in local_disjn:
|
||||||
if set(el.disjunctions_req) == set(d.disjunctions_req) and\
|
if set(elem.disjunctions_req) == set(dis_elem.disjunctions_req) and\
|
||||||
el.disjunction_id != d.disjunction_id:
|
elem.disjunction_id != dis_elem.disjunction_id:
|
||||||
local_disjn.remove(d)
|
local_disjn.remove(dis_elem)
|
||||||
return local_disjn
|
return local_disjn
|
||||||
|
|
||||||
|
|
||||||
def path_result_json(pathresult):
|
def path_result_json(pathresult):
|
||||||
|
""" create the response dictionnary
|
||||||
|
"""
|
||||||
data = {
|
data = {
|
||||||
'path': [n.json for n in pathresult]
|
'response': [n.json for n in pathresult]
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def compute_requests(network, data, equipment):
|
||||||
if __name__ == '__main__':
|
""" Main program calling functions
|
||||||
start = time.time()
|
"""
|
||||||
args = parser.parse_args()
|
|
||||||
basicConfig(level={2: DEBUG, 1: INFO, 0: CRITICAL}.get(args.verbose, DEBUG))
|
|
||||||
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)
|
|
||||||
data = load_requests(args.service_filename,args.eqpt_filename)
|
|
||||||
equipment = load_equipment(args.eqpt_filename)
|
|
||||||
network = load_network(args.network_filename,equipment)
|
|
||||||
|
|
||||||
# Build the network once using the default power defined in SI in eqpt config
|
# 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
|
# TODO power density: db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by
|
||||||
# spacing, f_min and f_max
|
# spacing, f_min and f_max
|
||||||
@@ -318,21 +379,30 @@ if __name__ == '__main__':
|
|||||||
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||||
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||||
build_network(network, equipment, p_db, p_total_db)
|
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)
|
||||||
|
|
||||||
|
try:
|
||||||
rqs = requests_from_json(data, equipment)
|
rqs = requests_from_json(data, equipment)
|
||||||
|
except ServiceError as this_e:
|
||||||
|
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}')
|
||||||
|
raise this_e
|
||||||
# check that request ids are unique. Non unique ids, may
|
# check that request ids are unique. Non unique ids, may
|
||||||
# mess the computation: better to stop the computation
|
# mess the computation: better to stop the computation
|
||||||
all_ids = [r.request_id for r in rqs]
|
all_ids = [r.request_id for r in rqs]
|
||||||
if len(all_ids) != len(set(all_ids)):
|
if len(all_ids) != len(set(all_ids)):
|
||||||
for a in list(set(all_ids)):
|
for item in list(set(all_ids)):
|
||||||
all_ids.remove(a)
|
all_ids.remove(item)
|
||||||
msg = f'Requests id {all_ids} are not unique'
|
msg = f'Requests id {all_ids} are not unique'
|
||||||
logger.critical(msg)
|
LOGGER.critical(msg)
|
||||||
exit()
|
raise ServiceError(msg)
|
||||||
|
try:
|
||||||
rqs = correct_route_list(network, rqs)
|
rqs = correct_route_list(network, rqs)
|
||||||
|
except ServiceError as this_e:
|
||||||
|
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}')
|
||||||
|
raise this_e
|
||||||
|
#exit(1)
|
||||||
# pths = compute_path(network, equipment, rqs)
|
# pths = compute_path(network, equipment, rqs)
|
||||||
dsjn = disjunctions_from_json(data)
|
dsjn = disjunctions_from_json(data)
|
||||||
|
|
||||||
@@ -352,25 +422,50 @@ if __name__ == '__main__':
|
|||||||
print(rqs)
|
print(rqs)
|
||||||
|
|
||||||
print('\x1b[1;34;40m' + f'Computing all paths with constraints' + '\x1b[0m')
|
print('\x1b[1;34;40m' + f'Computing all paths with constraints' + '\x1b[0m')
|
||||||
|
try:
|
||||||
pths = compute_path_dsjctn(network, equipment, rqs, dsjn)
|
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}')
|
||||||
|
raise this_e
|
||||||
|
|
||||||
print('\x1b[1;34;40m' + f'Propagating on selected path' + '\x1b[0m')
|
print('\x1b[1;34;40m' + f'Propagating on selected path' + '\x1b[0m')
|
||||||
propagatedpths = compute_path_with_disjunction(network, equipment, rqs, pths)
|
propagatedpths, reversed_pths, reversed_propagatedpths = \
|
||||||
|
compute_path_with_disjunction(network, equipment, rqs, pths)
|
||||||
|
# Note that deepcopy used in compute_path_with_disjunction returns
|
||||||
|
# a list of nodes which are not belonging to network (they are copies of the node objects).
|
||||||
|
# so there can not be propagation on these nodes.
|
||||||
|
|
||||||
|
pth_assign_spectrum(pths, rqs, oms_list, reversed_pths)
|
||||||
|
|
||||||
end = time.time()
|
|
||||||
print(f'computation time {end-start}')
|
|
||||||
print('\x1b[1;34;40m'+f'Result summary'+ '\x1b[0m')
|
print('\x1b[1;34;40m'+f'Result summary'+ '\x1b[0m')
|
||||||
|
header = ['req id', ' demand', ' snr@bandwidth A-Z (Z-A)', ' snr@0.1nm A-Z (Z-A)',\
|
||||||
header = ['req id', ' demand',' snr@bandwidth',' snr@0.1nm',' Receiver minOSNR', ' mode', ' Gbit/s' , ' nb of tsp pairs']
|
' Receiver minOSNR', ' mode', ' Gbit/s', ' nb of tsp pairs',\
|
||||||
|
'N,M or blocking reason']
|
||||||
data = []
|
data = []
|
||||||
data.append(header)
|
data.append(header)
|
||||||
for i, p in enumerate(propagatedpths):
|
for i, this_p in enumerate(propagatedpths):
|
||||||
if p:
|
rev_pth = reversed_propagatedpths[i]
|
||||||
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', f'{round(mean(p[-1].snr),2)}',\
|
if rev_pth and this_p:
|
||||||
f'{round(mean(p[-1].snr+lin2db(rqs[i].baud_rate/(12.5e9))),2)}',\
|
psnrb = f'{round(mean(this_p[-1].snr),2)} ({round(mean(rev_pth[-1].snr),2)})'
|
||||||
f'{rqs[i].OSNR}', f'{rqs[i].tsp_mode}' , f'{round(rqs[i].path_bandwidth * 1e-9,2)}' , f'{ceil(rqs[i].path_bandwidth / rqs[i].bit_rate) }']
|
psnr = f'{round(mean(this_p[-1].snr_01nm), 2)}' +\
|
||||||
|
f' ({round(mean(rev_pth[-1].snr_01nm),2)})'
|
||||||
|
elif this_p:
|
||||||
|
psnrb = f'{round(mean(this_p[-1].snr),2)}'
|
||||||
|
psnr = f'{round(mean(this_p[-1].snr_01nm),2)}'
|
||||||
|
|
||||||
|
try :
|
||||||
|
if rqs[i].blocking_reason in BLOCKING_NOPATH:
|
||||||
|
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} :',\
|
||||||
|
f'-', f'-', f'-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9,2)}',\
|
||||||
|
f'-', f'{rqs[i].blocking_reason}']
|
||||||
else:
|
else:
|
||||||
line = [f'{rqs[i].request_id}',f' {rqs[i].source} to {rqs[i].destination} : not feasible ']
|
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', psnrb,\
|
||||||
|
psnr, f'-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9, 2)}',\
|
||||||
|
f'-', f'{rqs[i].blocking_reason}']
|
||||||
|
except AttributeError:
|
||||||
|
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', psnrb,\
|
||||||
|
psnr, f'{rqs[i].OSNR}', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9,2)}',\
|
||||||
|
f'{ceil(rqs[i].path_bandwidth / rqs[i].bit_rate) }', f'({rqs[i].N},{rqs[i].M})']
|
||||||
data.append(line)
|
data.append(line)
|
||||||
|
|
||||||
col_width = max(len(word) for row in data for word in row[2:]) # padding
|
col_width = max(len(word) for row in data for word in row[2:]) # padding
|
||||||
@@ -381,19 +476,94 @@ if __name__ == '__main__':
|
|||||||
secondcol = ''.join(row[1].ljust(secondcol_width))
|
secondcol = ''.join(row[1].ljust(secondcol_width))
|
||||||
remainingcols = ''.join(word.center(col_width, ' ') for word in row[2:])
|
remainingcols = ''.join(word.center(col_width, ' ') for word in row[2:])
|
||||||
print(f'{firstcol} {secondcol} {remainingcols}')
|
print(f'{firstcol} {secondcol} {remainingcols}')
|
||||||
|
print('\x1b[1;33;40m'+f'Result summary shows mean SNR and OSNR (average over all channels)' +\
|
||||||
|
'\x1b[0m')
|
||||||
|
|
||||||
|
return propagatedpths, reversed_propagatedpths, rqs
|
||||||
|
|
||||||
|
|
||||||
if args.output :
|
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 = []
|
result = []
|
||||||
# assumes that list of rqs and list of propgatedpths have same order
|
# assumes that list of rqs and list of propgatedpths have same order
|
||||||
for i,p in enumerate(propagatedpths):
|
for i, pth in enumerate(propagatedpths):
|
||||||
result.append(Result_element(rqs[i],p))
|
result.append(Result_element(rqs[i], pth, reversed_propagatedpths[i]))
|
||||||
temp = path_result_json(result)
|
temp = path_result_json(result)
|
||||||
fnamecsv = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.csv'
|
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'
|
fnamejson = f'{str(ARGS.output)[0:len(str(ARGS.output))-len(str(ARGS.output.suffix))]}.json'
|
||||||
with open(fnamejson, 'w', encoding='utf-8') as f:
|
with open(fnamejson, 'w', encoding='utf-8') as fjson:
|
||||||
f.write(dumps(path_result_json(result), indent=2, ensure_ascii=False))
|
fjson.write(dumps(path_result_json(result), indent=2, ensure_ascii=False))
|
||||||
with open(fnamecsv, "w", encoding='utf-8') as fcsv:
|
with open(fnamecsv, "w", encoding='utf-8') as fcsv:
|
||||||
jsontocsv(temp, equipment, 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()
|
||||||
|
basicConfig(level={2: DEBUG, 1: INFO, 0: CRITICAL}.get(ARGS.verbose, DEBUG))
|
||||||
|
main(ARGS)
|
||||||
|
|||||||
98
examples/raman_edfa_example_network.json
Normal file
98
examples/raman_edfa_example_network.json
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
{
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"uid": "Site_A",
|
||||||
|
"type": "Transceiver",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"latitude": 0,
|
||||||
|
"longitude": 0,
|
||||||
|
"city": "Site A",
|
||||||
|
"region": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "Span1",
|
||||||
|
"type": "RamanFiber",
|
||||||
|
"type_variety": "SSMF",
|
||||||
|
"operational": {
|
||||||
|
"temperature": 283,
|
||||||
|
"raman_pumps": [
|
||||||
|
{
|
||||||
|
"power": 200e-3,
|
||||||
|
"frequency": 205e12,
|
||||||
|
"propagation_direction": "counterprop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"power": 206e-3,
|
||||||
|
"frequency": 201e12,
|
||||||
|
"propagation_direction": "counterprop"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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": "Edfa1",
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": 15.0,
|
||||||
|
"delta_p": -2,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": 0
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"latitude": 2,
|
||||||
|
"longitude": 0,
|
||||||
|
"city": null,
|
||||||
|
"region": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "Site_B",
|
||||||
|
"type": "Transceiver",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"latitude": 2,
|
||||||
|
"longitude": 0,
|
||||||
|
"city": "Site B",
|
||||||
|
"region": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"from_node": "Site_A",
|
||||||
|
"to_node": "Span1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "Span1",
|
||||||
|
"to_node": "Edfa1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "Edfa1",
|
||||||
|
"to_node": "Site_B"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
14
examples/sim_params.json
Normal file
14
examples/sim_params.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"raman_computed_channels": [1, 18, 37, 56, 75],
|
||||||
|
"raman_parameters": {
|
||||||
|
"flag_raman": true,
|
||||||
|
"space_resolution": 10e3,
|
||||||
|
"tolerance": 1e-8
|
||||||
|
},
|
||||||
|
"nli_parameters": {
|
||||||
|
"nli_method_name": "ggn_spectrally_separated",
|
||||||
|
"wdm_grid_size": 50e9,
|
||||||
|
"dispersion_tolerance": 1,
|
||||||
|
"phase_shift_tollerance": 0.1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
0.0359549,
|
0.0359549,
|
||||||
5.82851
|
5.82851
|
||||||
],
|
],
|
||||||
|
"f_min": 191.35e12,
|
||||||
|
"f_max": 196.1e12,
|
||||||
"nf_ripple": [
|
"nf_ripple": [
|
||||||
-0.3110761646066259,
|
-0.3110761646066259,
|
||||||
-0.3110761646066259,
|
-0.3110761646066259,
|
||||||
|
|||||||
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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -18,20 +18,21 @@ from pathlib import Path
|
|||||||
from json import loads
|
from json import loads
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from logging import getLogger, basicConfig, INFO, ERROR, DEBUG
|
from logging import getLogger, basicConfig, INFO, ERROR, DEBUG
|
||||||
from numpy import linspace, mean
|
from numpy import linspace, mean, log10
|
||||||
from matplotlib.pyplot import show, axis, figure, title
|
from matplotlib.pyplot import show, axis, figure, title, text
|
||||||
from networkx import (draw_networkx_nodes, draw_networkx_edges,
|
from networkx import (draw_networkx_nodes, draw_networkx_edges,
|
||||||
draw_networkx_labels, dijkstra_path)
|
draw_networkx_labels, dijkstra_path)
|
||||||
from gnpy.core.network import load_network, build_network, save_network
|
from gnpy.core.network import load_network, build_network, save_network, load_sim_params, configure_network
|
||||||
from gnpy.core.elements import Transceiver, Fiber, Edfa, Roadm
|
from gnpy.core.elements import Transceiver, Fiber, RamanFiber, Edfa, Roadm
|
||||||
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power, Pref
|
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power, Pref
|
||||||
from gnpy.core.request import Path_request, RequestParams, compute_constrained_path, propagate
|
from gnpy.core.request import Path_request, RequestParams, compute_constrained_path, propagate2
|
||||||
|
from gnpy.core.exceptions import ConfigurationError, EquipmentConfigError, NetworkTopologyError
|
||||||
|
import gnpy.core.ansi_escapes as ansi_escapes
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
def plot_results(network, path, source, destination):
|
def plot_baseline(network):
|
||||||
path_edges = set(zip(path[:-1], path[1:]))
|
edges = set(network.edges())
|
||||||
edges = set(network.edges()) - path_edges
|
|
||||||
pos = {n: (n.lng, n.lat) for n in network.nodes()}
|
pos = {n: (n.lng, n.lat) for n in network.nodes()}
|
||||||
labels = {n: n.location.city for n in network.nodes() if isinstance(n, Transceiver)}
|
labels = {n: n.location.city for n in network.nodes() if isinstance(n, Transceiver)}
|
||||||
city_labels = set(labels.values())
|
city_labels = set(labels.values())
|
||||||
@@ -44,16 +45,61 @@ def plot_results(network, path, source, destination):
|
|||||||
fig = figure()
|
fig = figure()
|
||||||
kwargs = {'figure': fig, 'pos': pos}
|
kwargs = {'figure': fig, 'pos': pos}
|
||||||
plot = draw_networkx_nodes(network, nodelist=network.nodes(), node_color='#ababab', **kwargs)
|
plot = draw_networkx_nodes(network, nodelist=network.nodes(), node_color='#ababab', **kwargs)
|
||||||
draw_networkx_nodes(network, nodelist=path, node_color='#ff0000', **kwargs)
|
draw_networkx_edges(network, edgelist=edges, edge_color='#ababab', **kwargs)
|
||||||
|
draw_networkx_labels(network, labels=labels, font_size=14, **{**kwargs, 'pos': label_pos})
|
||||||
|
axis('off')
|
||||||
|
show()
|
||||||
|
|
||||||
|
def plot_results(network, path, source, destination, infos):
|
||||||
|
path_edges = set(zip(path[:-1], path[1:]))
|
||||||
|
edges = set(network.edges()) - path_edges
|
||||||
|
pos = {n: (n.lng, n.lat) for n in network.nodes()}
|
||||||
|
nodes = {}
|
||||||
|
for k, (x, y) in pos.items():
|
||||||
|
nodes.setdefault((round(x, 1), round(y, 1)), []).append(k)
|
||||||
|
labels = {n: n.location.city for n in network.nodes() if isinstance(n, Transceiver)}
|
||||||
|
city_labels = set(labels.values())
|
||||||
|
for n in network.nodes():
|
||||||
|
if n.location.city and n.location.city not in city_labels:
|
||||||
|
labels[n] = n.location.city
|
||||||
|
city_labels.add(n.location.city)
|
||||||
|
label_pos = pos
|
||||||
|
|
||||||
|
fig = figure()
|
||||||
|
kwargs = {'figure': fig, 'pos': pos}
|
||||||
|
all_nodes = [n for n in network.nodes() if n not in path]
|
||||||
|
plot = draw_networkx_nodes(network, nodelist=all_nodes, node_color='#ababab', node_size=50, **kwargs)
|
||||||
|
draw_networkx_nodes(network, nodelist=path, node_color='#ff0000', node_size=55, **kwargs)
|
||||||
draw_networkx_edges(network, edgelist=edges, edge_color='#ababab', **kwargs)
|
draw_networkx_edges(network, edgelist=edges, edge_color='#ababab', **kwargs)
|
||||||
draw_networkx_edges(network, edgelist=path_edges, edge_color='#ff0000', **kwargs)
|
draw_networkx_edges(network, edgelist=path_edges, edge_color='#ff0000', **kwargs)
|
||||||
draw_networkx_labels(network, labels=labels, font_size=14, **{**kwargs, 'pos': label_pos})
|
draw_networkx_labels(network, labels=labels, font_size=14, **{**kwargs, 'pos': label_pos})
|
||||||
title(f'Propagating from {source.loc.city} to {destination.loc.city}')
|
title(f'Propagating from {source.loc.city} to {destination.loc.city}')
|
||||||
axis('off')
|
axis('off')
|
||||||
|
|
||||||
|
heading = 'Spectral Information\n\n'
|
||||||
|
textbox = text(0.85, 0.20, heading, fontsize=14, fontname='Ubuntu Mono',
|
||||||
|
verticalalignment='top', transform=fig.axes[0].transAxes,
|
||||||
|
bbox={'boxstyle': 'round', 'facecolor': 'wheat', 'alpha': 0.5})
|
||||||
|
|
||||||
|
msgs = {(x, y): heading + '\n\n'.join(str(n) for n in ns if n in path)
|
||||||
|
for (x, y), ns in nodes.items()}
|
||||||
|
|
||||||
|
def hover(event):
|
||||||
|
if event.xdata is None or event.ydata is None:
|
||||||
|
return
|
||||||
|
if fig.contains(event):
|
||||||
|
x, y = round(event.xdata, 1), round(event.ydata, 1)
|
||||||
|
if (x, y) in msgs:
|
||||||
|
textbox.set_text(msgs[x, y])
|
||||||
|
else:
|
||||||
|
textbox.set_text(heading)
|
||||||
|
fig.canvas.draw_idle()
|
||||||
|
|
||||||
|
fig.canvas.mpl_connect('motion_notify_event', hover)
|
||||||
show()
|
show()
|
||||||
|
|
||||||
|
|
||||||
def main(network, equipment, source, destination, req = None):
|
def main(network, equipment, source, destination, sim_params, req=None):
|
||||||
result_dicts = {}
|
result_dicts = {}
|
||||||
network_data = [{
|
network_data = [{
|
||||||
'network_name' : str(args.filename),
|
'network_name' : str(args.filename),
|
||||||
@@ -62,8 +108,8 @@ def main(network, equipment, source, destination, req = None):
|
|||||||
}]
|
}]
|
||||||
result_dicts.update({'network': network_data})
|
result_dicts.update({'network': network_data})
|
||||||
design_data = [{
|
design_data = [{
|
||||||
'power_mode' : equipment['Spans']['default'].power_mode,
|
'power_mode' : equipment['Span']['default'].power_mode,
|
||||||
'span_power_range' : equipment['Spans']['default'].delta_power_range_db,
|
'span_power_range' : equipment['Span']['default'].delta_power_range_db,
|
||||||
'design_pch' : equipment['SI']['default'].power_dbm,
|
'design_pch' : equipment['SI']['default'].power_dbm,
|
||||||
'baud_rate' : equipment['SI']['default'].baud_rate
|
'baud_rate' : equipment['SI']['default'].baud_rate
|
||||||
}]
|
}]
|
||||||
@@ -71,17 +117,23 @@ def main(network, equipment, source, destination, req = None):
|
|||||||
simulation_data = []
|
simulation_data = []
|
||||||
result_dicts.update({'simulation results': simulation_data})
|
result_dicts.update({'simulation results': simulation_data})
|
||||||
|
|
||||||
power_mode = equipment['Spans']['default'].power_mode
|
power_mode = equipment['Span']['default'].power_mode
|
||||||
print('\n'.join([f'Power mode is set to {power_mode}',
|
print('\n'.join([f'Power mode is set to {power_mode}',
|
||||||
f'=> it can be modified in eqpt_config.json - Spans']))
|
f'=> it can be modified in eqpt_config.json - Span']))
|
||||||
|
|
||||||
pref_ch_db = lin2db(req.power*1e3) #reference channel power / span (SL=20dB)
|
pref_ch_db = lin2db(req.power*1e3) #reference channel power / span (SL=20dB)
|
||||||
pref_total_db = pref_ch_db + lin2db(req.nb_channel) #reference total power / span (SL=20dB)
|
pref_total_db = pref_ch_db + lin2db(req.nb_channel) #reference total power / span (SL=20dB)
|
||||||
build_network(network, equipment, pref_ch_db, pref_total_db)
|
build_network(network, equipment, pref_ch_db, pref_total_db)
|
||||||
path = compute_constrained_path(network, req)
|
path = compute_constrained_path(network, req)
|
||||||
|
|
||||||
spans = [s.length for s in path if isinstance(s, Fiber)]
|
if len([s.length for s in path if isinstance(s, RamanFiber)]):
|
||||||
print(f'\nThere are {len(spans)} fiber spans over {sum(spans):.0f}m between {source.uid} and {destination.uid}')
|
if sim_params is None:
|
||||||
|
print(f'{ansi_escapes.red}Invocation error:{ansi_escapes.reset} RamanFiber requires passing simulation params via --sim-params')
|
||||||
|
exit(1)
|
||||||
|
configure_network(network, sim_params)
|
||||||
|
|
||||||
|
spans = [s.length for s in path if isinstance(s, RamanFiber) or isinstance(s, Fiber)]
|
||||||
|
print(f'\nThere are {len(spans)} fiber spans over {sum(spans)/1000:.0f} km between {source.uid} and {destination.uid}')
|
||||||
print(f'\nNow propagating between {source.uid} and {destination.uid}:')
|
print(f'\nNow propagating between {source.uid} and {destination.uid}:')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -92,18 +144,32 @@ def main(network, equipment, source, destination, req = None):
|
|||||||
print('invalid power range definition in eqpt_config, should be power_range_db: [lower, upper, step]')
|
print('invalid power range definition in eqpt_config, should be power_range_db: [lower, upper, step]')
|
||||||
power_range = [0]
|
power_range = [0]
|
||||||
|
|
||||||
|
if not power_mode:
|
||||||
|
#power cannot be changed in gain mode
|
||||||
|
power_range = [0]
|
||||||
for dp_db in power_range:
|
for dp_db in power_range:
|
||||||
req.power = db2lin(pref_ch_db + dp_db)*1e-3
|
req.power = db2lin(pref_ch_db + dp_db)*1e-3
|
||||||
print(f'\nPropagating with input power = {lin2db(req.power*1e3):.2f}dBm :')
|
if power_mode:
|
||||||
propagate(path, req, equipment, show=len(power_range)==1)
|
print(f'\nPropagating with input power = {ansi_escapes.cyan}{lin2db(req.power*1e3):.2f} dBm{ansi_escapes.reset}:')
|
||||||
|
else:
|
||||||
|
print(f'\nPropagating in {ansi_escapes.cyan}gain mode{ansi_escapes.reset}: power cannot be set manually')
|
||||||
|
infos = propagate2(path, req, equipment)
|
||||||
|
if len(power_range) == 1:
|
||||||
|
for elem in path:
|
||||||
|
print(elem)
|
||||||
|
if power_mode:
|
||||||
print(f'\nTransmission result for input power = {lin2db(req.power*1e3):.2f} dBm:')
|
print(f'\nTransmission result for input power = {lin2db(req.power*1e3):.2f} dBm:')
|
||||||
print(destination)
|
else:
|
||||||
|
print(f'\nTransmission results:')
|
||||||
|
print(f' Final SNR total (0.1 nm): {ansi_escapes.cyan}{mean(destination.snr_01nm):.02f} dB{ansi_escapes.reset}')
|
||||||
|
else:
|
||||||
|
print(path[-1])
|
||||||
|
|
||||||
#print(f'\n !!!!!!!!!!!!!!!!! TEST POINT !!!!!!!!!!!!!!!!!!!!!')
|
#print(f'\n !!!!!!!!!!!!!!!!! TEST POINT !!!!!!!!!!!!!!!!!!!!!')
|
||||||
#print(f'carriers ase output of {path[1]} =\n {list(path[1].carriers("out", "nli"))}')
|
#print(f'carriers ase output of {path[1]} =\n {list(path[1].carriers("out", "nli"))}')
|
||||||
# => use "in" or "out" parameter
|
# => use "in" or "out" parameter
|
||||||
# => use "nli" or "ase" or "signal" or "total" parameter
|
# => use "nli" or "ase" or "signal" or "total" parameter
|
||||||
|
if power_mode:
|
||||||
simulation_data.append({
|
simulation_data.append({
|
||||||
'Pch_dBm' : pref_ch_db + dp_db,
|
'Pch_dBm' : pref_ch_db + dp_db,
|
||||||
'OSNR_ASE_0.1nm' : round(mean(destination.osnr_ase_01nm),2),
|
'OSNR_ASE_0.1nm' : round(mean(destination.osnr_ase_01nm),2),
|
||||||
@@ -111,20 +177,29 @@ def main(network, equipment, source, destination, req = None):
|
|||||||
'SNR_nli_signal_bw' : round(mean(destination.osnr_nli),2),
|
'SNR_nli_signal_bw' : round(mean(destination.osnr_nli),2),
|
||||||
'SNR_total_signal_bw' : round(mean(destination.snr),2)
|
'SNR_total_signal_bw' : round(mean(destination.snr),2)
|
||||||
})
|
})
|
||||||
|
else:
|
||||||
|
simulation_data.append({
|
||||||
|
'gain_mode' : 'power canot be set',
|
||||||
|
'OSNR_ASE_0.1nm' : round(mean(destination.osnr_ase_01nm),2),
|
||||||
|
'OSNR_ASE_signal_bw' : round(mean(destination.osnr_ase),2),
|
||||||
|
'SNR_nli_signal_bw' : round(mean(destination.osnr_nli),2),
|
||||||
|
'SNR_total_signal_bw' : round(mean(destination.snr),2)
|
||||||
|
})
|
||||||
write_csv(result_dicts, 'simulation_result.csv')
|
write_csv(result_dicts, 'simulation_result.csv')
|
||||||
return path
|
return path, infos
|
||||||
|
|
||||||
|
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
parser.add_argument('-e', '--equipment', type=Path,
|
parser.add_argument('-e', '--equipment', type=Path,
|
||||||
default=Path(__file__).parent / 'eqpt_config.json')
|
default=Path(__file__).parent / 'eqpt_config.json')
|
||||||
|
parser.add_argument('--sim-params', type=Path,
|
||||||
|
default=None, help='Path to the JSON containing simulation parameters (required for Raman)')
|
||||||
|
parser.add_argument('--show-channels', action='store_true', help='Show final per-channel OSNR summary')
|
||||||
parser.add_argument('-pl', '--plot', action='store_true')
|
parser.add_argument('-pl', '--plot', action='store_true')
|
||||||
parser.add_argument('-v', '--verbose', action='count', default=0, help='increases verbosity for each occurence')
|
parser.add_argument('-v', '--verbose', action='count', default=0, help='increases verbosity for each occurence')
|
||||||
parser.add_argument('-l', '--list-nodes', action='store_true', help='list all transceiver nodes')
|
parser.add_argument('-l', '--list-nodes', action='store_true', help='list all transceiver nodes')
|
||||||
parser.add_argument('-po', '--power', default=0, help='channel ref power in dBm')
|
parser.add_argument('-po', '--power', default=0, help='channel ref power in dBm')
|
||||||
parser.add_argument('-names', '--names-matching', action='store_true', help='display network names that are closed matches')
|
parser.add_argument('-names', '--names-matching', action='store_true', help='display network names that are closed matches')
|
||||||
#parser.add_argument('-plb', '--power-lower-bound', default=0, help='power sweep lower bound')
|
|
||||||
#parser.add_argument('-pub', '--power-upper-bound', default=1, help='power sweep upper bound')
|
|
||||||
parser.add_argument('filename', nargs='?', type=Path,
|
parser.add_argument('filename', nargs='?', type=Path,
|
||||||
default=Path(__file__).parent / 'edfa_example_network.json')
|
default=Path(__file__).parent / 'edfa_example_network.json')
|
||||||
parser.add_argument('source', nargs='?', help='source node')
|
parser.add_argument('source', nargs='?', help='source node')
|
||||||
@@ -135,11 +210,22 @@ if __name__ == '__main__':
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
basicConfig(level={0: ERROR, 1: INFO, 2: DEBUG}.get(args.verbose, DEBUG))
|
basicConfig(level={0: ERROR, 1: INFO, 2: DEBUG}.get(args.verbose, DEBUG))
|
||||||
|
|
||||||
|
try:
|
||||||
equipment = load_equipment(args.equipment)
|
equipment = load_equipment(args.equipment)
|
||||||
# logger.info(equipment)
|
|
||||||
# print(args.filename)
|
|
||||||
network = load_network(args.filename, equipment, args.names_matching)
|
network = load_network(args.filename, equipment, args.names_matching)
|
||||||
# print(network)
|
sim_params = load_sim_params(args.sim_params) if args.sim_params is not None else None
|
||||||
|
except EquipmentConfigError as e:
|
||||||
|
print(f'{ansi_escapes.red}Configuration error in the equipment library:{ansi_escapes.reset} {e}')
|
||||||
|
exit(1)
|
||||||
|
except NetworkTopologyError as e:
|
||||||
|
print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}')
|
||||||
|
exit(1)
|
||||||
|
except ConfigurationError as e:
|
||||||
|
print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if args.plot:
|
||||||
|
plot_baseline(network)
|
||||||
|
|
||||||
transceivers = {n.uid: n for n in network.nodes() if isinstance(n, Transceiver)}
|
transceivers = {n.uid: n for n in network.nodes() if isinstance(n, Transceiver)}
|
||||||
|
|
||||||
@@ -196,6 +282,7 @@ if __name__ == '__main__':
|
|||||||
params['trx_mode'] = ''
|
params['trx_mode'] = ''
|
||||||
params['source'] = source.uid
|
params['source'] = source.uid
|
||||||
params['destination'] = destination.uid
|
params['destination'] = destination.uid
|
||||||
|
params['bidir'] = False
|
||||||
params['nodes_list'] = [destination.uid]
|
params['nodes_list'] = [destination.uid]
|
||||||
params['loose_list'] = ['strict']
|
params['loose_list'] = ['strict']
|
||||||
params['format'] = ''
|
params['format'] = ''
|
||||||
@@ -205,9 +292,19 @@ if __name__ == '__main__':
|
|||||||
trx_params['power'] = db2lin(float(args.power))*1e-3
|
trx_params['power'] = db2lin(float(args.power))*1e-3
|
||||||
params.update(trx_params)
|
params.update(trx_params)
|
||||||
req = Path_request(**params)
|
req = Path_request(**params)
|
||||||
path = main(network, equipment, source, destination, req)
|
path, infos = main(network, equipment, source, destination, sim_params, req)
|
||||||
save_network(args.filename, network)
|
save_network(args.filename, network)
|
||||||
|
|
||||||
|
if args.show_channels:
|
||||||
|
print('\nThe total SNR per channel at the end of the line is:')
|
||||||
|
print('{:>5}{:>26}{:>26}{:>28}{:>28}{:>28}' \
|
||||||
|
.format('Ch. #', 'Channel frequency (THz)', 'Channel power (dBm)', 'OSNR ASE (signal bw, dB)', 'SNR NLI (signal bw, dB)', 'SNR total (signal bw, dB)'))
|
||||||
|
for final_carrier, ch_osnr, ch_snr_nl, ch_snr in zip(infos[path[-1]][1].carriers, path[-1].osnr_ase, path[-1].osnr_nli, path[-1].snr):
|
||||||
|
ch_freq = final_carrier.frequency * 1e-12
|
||||||
|
ch_power = lin2db(final_carrier.power.signal*1e3)
|
||||||
|
print('{:5}{:26.2f}{:26.2f}{:28.2f}{:28.2f}{:28.2f}' \
|
||||||
|
.format(final_carrier.channel_number, round(ch_freq, 2), round(ch_power, 2), round(ch_osnr, 2), round(ch_snr_nl, 2), round(ch_snr, 2)))
|
||||||
|
|
||||||
if not args.source:
|
if not args.source:
|
||||||
print(f'\n(No source node specified: picked {source.uid})')
|
print(f'\n(No source node specified: picked {source.uid})')
|
||||||
elif not valid_source:
|
elif not valid_source:
|
||||||
@@ -219,4 +316,4 @@ if __name__ == '__main__':
|
|||||||
print(f'\n(Invalid destination node {args.destination!r} replaced with {destination.uid})')
|
print(f'\n(Invalid destination node {args.destination!r} replaced with {destination.uid})')
|
||||||
|
|
||||||
if args.plot:
|
if args.plot:
|
||||||
plot_results(network, path, source, destination)
|
plot_results(network, path, source, destination, infos)
|
||||||
|
|||||||
13
gnpy/core/ansi_escapes.py
Normal file
13
gnpy/core/ansi_escapes.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
gnpy.core.ansi_escapes
|
||||||
|
======================
|
||||||
|
|
||||||
|
A random subset of ANSI terminal escape codes for colored messages
|
||||||
|
'''
|
||||||
|
|
||||||
|
red = '\x1b[1;31;40m'
|
||||||
|
cyan = '\x1b[1;36;40m'
|
||||||
|
reset = '\x1b[0m'
|
||||||
@@ -31,6 +31,8 @@ from itertools import chain
|
|||||||
from json import dumps
|
from json import dumps
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from difflib import get_close_matches
|
from difflib import get_close_matches
|
||||||
|
from gnpy.core.utils import silent_remove
|
||||||
|
from gnpy.core.exceptions import NetworkTopologyError
|
||||||
import time
|
import time
|
||||||
|
|
||||||
all_rows = lambda sh, start=0: (sh.row(x) for x in range(start, sh.nrows))
|
all_rows = lambda sh, start=0: (sh.row(x) for x in range(start, sh.nrows))
|
||||||
@@ -54,7 +56,9 @@ class Node(object):
|
|||||||
'region': '',
|
'region': '',
|
||||||
'latitude': 0,
|
'latitude': 0,
|
||||||
'longitude': 0,
|
'longitude': 0,
|
||||||
'node_type': 'ILA'
|
'node_type': 'ILA',
|
||||||
|
'booster_restriction' : '',
|
||||||
|
'preamp_restriction' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
class Link(object):
|
class Link(object):
|
||||||
@@ -113,9 +117,10 @@ class Eqpt(object):
|
|||||||
'to_city': '',
|
'to_city': '',
|
||||||
'east_amp_type': '',
|
'east_amp_type': '',
|
||||||
'east_att_in': 0,
|
'east_att_in': 0,
|
||||||
'east_amp_gain': 0,
|
'east_amp_gain': None,
|
||||||
|
'east_amp_dp': None,
|
||||||
'east_tilt': 0,
|
'east_tilt': 0,
|
||||||
'east_att_out': 0
|
'east_att_out': None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -128,7 +133,7 @@ def read_header(my_sheet, line, slice_):
|
|||||||
try:
|
try:
|
||||||
header = [x.value.strip() for x in my_sheet.row_slice(line, slice_[0], slice_[1])]
|
header = [x.value.strip() for x in my_sheet.row_slice(line, slice_[0], slice_[1])]
|
||||||
header_i = [Param_header(header,i+slice_[0]) for i, header in enumerate(header) if header != '']
|
header_i = [Param_header(header,i+slice_[0]) for i, header in enumerate(header) if header != '']
|
||||||
except:
|
except Exception:
|
||||||
header_i = []
|
header_i = []
|
||||||
if header_i != [] and header_i[-1].colindex != slice_[1]:
|
if header_i != [] and header_i[-1].colindex != slice_[1]:
|
||||||
header_i.append(Param_header('',slice_[1]))
|
header_i.append(Param_header('',slice_[1]))
|
||||||
@@ -143,7 +148,7 @@ def read_slice(my_sheet, line, slice_, header):
|
|||||||
try:
|
try:
|
||||||
slice_range = next((h.colindex,header_i[i+1].colindex) \
|
slice_range = next((h.colindex,header_i[i+1].colindex) \
|
||||||
for i,h in enumerate(header_i) if header in h.header)
|
for i,h in enumerate(header_i) if header in h.header)
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
return slice_range
|
return slice_range
|
||||||
|
|
||||||
@@ -163,8 +168,8 @@ def parse_headers(my_sheet, input_headers_dict, headers, start_line, slice_in):
|
|||||||
slice_out = read_slice(my_sheet, start_line+iteration, slice_in, h0)
|
slice_out = read_slice(my_sheet, start_line+iteration, slice_in, h0)
|
||||||
iteration += 1
|
iteration += 1
|
||||||
if slice_out == (-1, -1):
|
if slice_out == (-1, -1):
|
||||||
if h0 == 'east':
|
if h0 in ('east', 'Node A', 'Node Z', 'City') :
|
||||||
print(f'\x1b[1;31;40m'+f'CRITICAL: missing _east_ header above other headers (hierarchical) _ ABORT'+ '\x1b[0m')
|
print(f'\x1b[1;31;40m'+f'CRITICAL: missing _{h0}_ header: EXECUTION ENDS'+ '\x1b[0m')
|
||||||
exit()
|
exit()
|
||||||
else:
|
else:
|
||||||
print(f'missing header {h0}')
|
print(f'missing header {h0}')
|
||||||
@@ -234,7 +239,6 @@ def sanity_check(nodes, links, nodes_by_city, links_by_city, eqpts_by_city):
|
|||||||
|
|
||||||
def convert_file(input_filename, names_matching=False, filter_region=[]):
|
def convert_file(input_filename, names_matching=False, filter_region=[]):
|
||||||
nodes, links, eqpts = parse_excel(input_filename)
|
nodes, links, eqpts = parse_excel(input_filename)
|
||||||
|
|
||||||
if filter_region:
|
if filter_region:
|
||||||
nodes = [n for n in nodes if n.region.lower() in filter_region]
|
nodes = [n for n in nodes if n.region.lower() in filter_region]
|
||||||
cities = {n.city for n in nodes}
|
cities = {n.city for n in nodes}
|
||||||
@@ -243,10 +247,8 @@ def convert_file(input_filename, names_matching=False, filter_region=[]):
|
|||||||
cities = {lnk.from_city for lnk in links} | {lnk.to_city for lnk in links}
|
cities = {lnk.from_city for lnk in links} | {lnk.to_city for lnk in links}
|
||||||
nodes = [n for n in nodes if n.city in cities]
|
nodes = [n for n in nodes if n.city in cities]
|
||||||
|
|
||||||
|
|
||||||
global nodes_by_city
|
global nodes_by_city
|
||||||
nodes_by_city = {n.city: n for n in nodes}
|
nodes_by_city = {n.city: n for n in nodes}
|
||||||
|
|
||||||
#create matching dictionary for node name mismatch analysis
|
#create matching dictionary for node name mismatch analysis
|
||||||
|
|
||||||
cities = {''.join(c.strip() for c in n.city.split('C+L')).lower(): n.city for n in nodes}
|
cities = {''.join(c.strip() for c in n.city.split('C+L')).lower(): n.city for n in nodes}
|
||||||
@@ -297,7 +299,22 @@ def convert_file(input_filename, names_matching=False, filter_region=[]):
|
|||||||
'latitude': x.latitude,
|
'latitude': x.latitude,
|
||||||
'longitude': x.longitude}},
|
'longitude': x.longitude}},
|
||||||
'type': 'Roadm'}
|
'type': 'Roadm'}
|
||||||
for x in nodes_by_city.values() if x.node_type.lower() == 'roadm'] +
|
for x in nodes_by_city.values() if x.node_type.lower() == 'roadm' \
|
||||||
|
and x.booster_restriction == '' and x.preamp_restriction == ''] +
|
||||||
|
[{'uid': f'roadm {x.city}',
|
||||||
|
'params' : {
|
||||||
|
'restrictions': {
|
||||||
|
'preamp_variety_list': silent_remove(x.preamp_restriction.split(' | '),''),
|
||||||
|
'booster_variety_list': silent_remove(x.booster_restriction.split(' | '),'')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'metadata': {'location': {'city': x.city,
|
||||||
|
'region': x.region,
|
||||||
|
'latitude': x.latitude,
|
||||||
|
'longitude': x.longitude}},
|
||||||
|
'type': 'Roadm'}
|
||||||
|
for x in nodes_by_city.values() if x.node_type.lower() == 'roadm' and \
|
||||||
|
(x.booster_restriction != '' or x.preamp_restriction != '')] +
|
||||||
[{'uid': f'west fused spans in {x.city}',
|
[{'uid': f'west fused spans in {x.city}',
|
||||||
'metadata': {'location': {'city': x.city,
|
'metadata': {'location': {'city': x.city,
|
||||||
'region': x.region,
|
'region': x.region,
|
||||||
@@ -344,10 +361,12 @@ def convert_file(input_filename, names_matching=False, filter_region=[]):
|
|||||||
'type': 'Edfa',
|
'type': 'Edfa',
|
||||||
'type_variety': e.east_amp_type,
|
'type_variety': e.east_amp_type,
|
||||||
'operational': {'gain_target': e.east_amp_gain,
|
'operational': {'gain_target': e.east_amp_gain,
|
||||||
|
'delta_p': e.east_amp_dp,
|
||||||
'tilt_target': e.east_tilt,
|
'tilt_target': e.east_tilt,
|
||||||
'out_voa' : e.east_att_out}
|
'out_voa' : e.east_att_out}
|
||||||
}
|
}
|
||||||
for e in eqpts if e.east_amp_type.lower() != ''] +
|
for e in eqpts if (e.east_amp_type.lower() != '' and \
|
||||||
|
e.east_amp_type.lower() != 'fused')] +
|
||||||
[{'uid': f'west edfa in {e.from_city} to {e.to_city}',
|
[{'uid': f'west edfa in {e.from_city} to {e.to_city}',
|
||||||
'metadata': {'location': {'city': nodes_by_city[e.from_city].city,
|
'metadata': {'location': {'city': nodes_by_city[e.from_city].city,
|
||||||
'region': nodes_by_city[e.from_city].region,
|
'region': nodes_by_city[e.from_city].region,
|
||||||
@@ -356,10 +375,34 @@ def convert_file(input_filename, names_matching=False, filter_region=[]):
|
|||||||
'type': 'Edfa',
|
'type': 'Edfa',
|
||||||
'type_variety': e.west_amp_type,
|
'type_variety': e.west_amp_type,
|
||||||
'operational': {'gain_target': e.west_amp_gain,
|
'operational': {'gain_target': e.west_amp_gain,
|
||||||
|
'delta_p': e.west_amp_dp,
|
||||||
'tilt_target': e.west_tilt,
|
'tilt_target': e.west_tilt,
|
||||||
'out_voa' : e.west_att_out}
|
'out_voa' : e.west_att_out}
|
||||||
}
|
}
|
||||||
for e in eqpts if e.west_amp_type.lower() != ''],
|
for e in eqpts if (e.west_amp_type.lower() != '' and \
|
||||||
|
e.west_amp_type.lower() != 'fused')] +
|
||||||
|
# fused edfa variety is a hack to indicate that there should not be
|
||||||
|
# booster amplifier out the roadm.
|
||||||
|
# If user specifies ILA in Nodes sheet and fused in Eqpt sheet, then assumes that
|
||||||
|
# this is a fused nodes.
|
||||||
|
[{'uid': f'east edfa in {e.from_city} to {e.to_city}',
|
||||||
|
'metadata': {'location': {'city': nodes_by_city[e.from_city].city,
|
||||||
|
'region': nodes_by_city[e.from_city].region,
|
||||||
|
'latitude': nodes_by_city[e.from_city].latitude,
|
||||||
|
'longitude': nodes_by_city[e.from_city].longitude}},
|
||||||
|
'type': 'Fused',
|
||||||
|
'params': {'loss': 0}
|
||||||
|
}
|
||||||
|
for e in eqpts if e.east_amp_type.lower() == 'fused'] +
|
||||||
|
[{'uid': f'west edfa in {e.from_city} to {e.to_city}',
|
||||||
|
'metadata': {'location': {'city': nodes_by_city[e.from_city].city,
|
||||||
|
'region': nodes_by_city[e.from_city].region,
|
||||||
|
'latitude': nodes_by_city[e.from_city].latitude,
|
||||||
|
'longitude': nodes_by_city[e.from_city].longitude}},
|
||||||
|
'type': 'Fused',
|
||||||
|
'params': {'loss': 0}
|
||||||
|
}
|
||||||
|
for e in eqpts if e.west_amp_type.lower() == 'fused'],
|
||||||
'connections':
|
'connections':
|
||||||
list(chain.from_iterable([eqpt_connection_by_city(n.city)
|
list(chain.from_iterable([eqpt_connection_by_city(n.city)
|
||||||
for n in nodes]))
|
for n in nodes]))
|
||||||
@@ -411,7 +454,9 @@ def parse_excel(input_filename):
|
|||||||
'Region': 'region',
|
'Region': 'region',
|
||||||
'Latitude': 'latitude',
|
'Latitude': 'latitude',
|
||||||
'Longitude': 'longitude',
|
'Longitude': 'longitude',
|
||||||
'Type': 'node_type'
|
'Type': 'node_type',
|
||||||
|
'Booster_restriction': 'booster_restriction',
|
||||||
|
'Preamp_restriction': 'preamp_restriction'
|
||||||
}
|
}
|
||||||
eqpt_headers = \
|
eqpt_headers = \
|
||||||
{ 'Node A': 'from_city',
|
{ 'Node A': 'from_city',
|
||||||
@@ -420,6 +465,7 @@ def parse_excel(input_filename):
|
|||||||
'amp type': 'east_amp_type',
|
'amp type': 'east_amp_type',
|
||||||
'att_in': 'east_att_in',
|
'att_in': 'east_att_in',
|
||||||
'amp gain': 'east_amp_gain',
|
'amp gain': 'east_amp_gain',
|
||||||
|
'delta p': 'east_amp_dp',
|
||||||
'tilt': 'east_tilt',
|
'tilt': 'east_tilt',
|
||||||
'att_out': 'east_att_out'
|
'att_out': 'east_att_out'
|
||||||
},
|
},
|
||||||
@@ -427,6 +473,7 @@ def parse_excel(input_filename):
|
|||||||
'amp type': 'west_amp_type',
|
'amp type': 'west_amp_type',
|
||||||
'att_in': 'west_att_in',
|
'att_in': 'west_att_in',
|
||||||
'amp gain': 'west_amp_gain',
|
'amp gain': 'west_amp_gain',
|
||||||
|
'delta p': 'west_amp_dp',
|
||||||
'tilt': 'west_tilt',
|
'tilt': 'west_tilt',
|
||||||
'att_out': 'west_att_out'
|
'att_out': 'west_att_out'
|
||||||
}
|
}
|
||||||
@@ -437,16 +484,16 @@ def parse_excel(input_filename):
|
|||||||
links_sheet = wb.sheet_by_name('Links')
|
links_sheet = wb.sheet_by_name('Links')
|
||||||
try:
|
try:
|
||||||
eqpt_sheet = wb.sheet_by_name('Eqpt')
|
eqpt_sheet = wb.sheet_by_name('Eqpt')
|
||||||
except:
|
except Exception:
|
||||||
#eqpt_sheet is optional
|
#eqpt_sheet is optional
|
||||||
eqpt_sheet = None
|
eqpt_sheet = None
|
||||||
|
|
||||||
nodes = []
|
nodes = []
|
||||||
for node in parse_sheet(nodes_sheet, node_headers, NODES_LINE, NODES_LINE+1, NODES_COLUMN):
|
for node in parse_sheet(nodes_sheet, node_headers, NODES_LINE, NODES_LINE+1, NODES_COLUMN):
|
||||||
nodes.append(Node(**node))
|
nodes.append(Node(**node))
|
||||||
expected_node_types = ('ROADM', 'ILA', 'FUSED')
|
expected_node_types = {'ROADM', 'ILA', 'FUSED'}
|
||||||
for n in nodes:
|
for n in nodes:
|
||||||
if not (n.node_type in expected_node_types):
|
if n.node_type not in expected_node_types:
|
||||||
n.node_type = 'ILA'
|
n.node_type = 'ILA'
|
||||||
|
|
||||||
links = []
|
links = []
|
||||||
@@ -462,10 +509,13 @@ def parse_excel(input_filename):
|
|||||||
# sanity check
|
# sanity check
|
||||||
all_cities = Counter(n.city for n in nodes)
|
all_cities = Counter(n.city for n in nodes)
|
||||||
if len(all_cities) != len(nodes):
|
if len(all_cities) != len(nodes):
|
||||||
ValueError(f'Duplicate city: {all_cities}')
|
raise ValueError(f'Duplicate city: {all_cities}')
|
||||||
if any(ln.from_city not in all_cities or
|
bad_links = []
|
||||||
ln.to_city not in all_cities for ln in links):
|
for lnk in links:
|
||||||
ValueError(f'Bad link.')
|
if lnk.from_city not in all_cities or lnk.to_city not in all_cities:
|
||||||
|
bad_links.append([lnk.from_city, lnk.to_city])
|
||||||
|
if bad_links:
|
||||||
|
raise NetworkTopologyError(f'Bad link(s): {bad_links}.')
|
||||||
|
|
||||||
return nodes, links, eqpts
|
return nodes, links, eqpts
|
||||||
|
|
||||||
@@ -473,7 +523,7 @@ def parse_excel(input_filename):
|
|||||||
def eqpt_connection_by_city(city_name):
|
def eqpt_connection_by_city(city_name):
|
||||||
other_cities = fiber_dest_from_source(city_name)
|
other_cities = fiber_dest_from_source(city_name)
|
||||||
subdata = []
|
subdata = []
|
||||||
if nodes_by_city[city_name].node_type.lower() in ('ila', 'fused'):
|
if nodes_by_city[city_name].node_type.lower() in {'ila', 'fused'}:
|
||||||
# Then len(other_cities) == 2
|
# Then len(other_cities) == 2
|
||||||
direction = ['west', 'east']
|
direction = ['west', 'east']
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
@@ -566,12 +616,12 @@ def midpoint(city_a, city_b):
|
|||||||
#output_json_file_name = 'coronet_conus_example.json'
|
#output_json_file_name = 'coronet_conus_example.json'
|
||||||
#TODO get column size automatically from tupple size
|
#TODO get column size automatically from tupple size
|
||||||
|
|
||||||
NODES_COLUMN = 7
|
NODES_COLUMN = 10
|
||||||
NODES_LINE = 4
|
NODES_LINE = 4
|
||||||
LINKS_COLUMN = 16
|
LINKS_COLUMN = 16
|
||||||
LINKS_LINE = 3
|
LINKS_LINE = 3
|
||||||
EQPTS_LINE = 3
|
EQPTS_LINE = 3
|
||||||
EQPTS_COLUMN = 12
|
EQPTS_COLUMN = 14
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
parser.add_argument('workbook', nargs='?', type=Path , default='meshTopologyExampleV2.xls')
|
parser.add_argument('workbook', nargs='?', type=Path , default='meshTopologyExampleV2.xls')
|
||||||
parser.add_argument('-f', '--filter-region', action='append', default=[])
|
parser.add_argument('-f', '--filter-region', action='append', default=[])
|
||||||
|
|||||||
@@ -7,25 +7,26 @@ gnpy.core.elements
|
|||||||
|
|
||||||
This module contains standard network elements.
|
This module contains standard network elements.
|
||||||
|
|
||||||
A network element is a Python callable. It takes a .info.SpectralInformation
|
A network element is a Python callable. It takes a :class:`.info.SpectralInformation`
|
||||||
object and returns a copy with appropriate fields affected. This structure
|
object and returns a copy with appropriate fields affected. This structure
|
||||||
represents spectral information that is "propogated" by this network element.
|
represents spectral information that is "propogated" by this network element.
|
||||||
Network elements must have only a local "view" of the network and propogate
|
Network elements must have only a local "view" of the network and propogate
|
||||||
SpectralInformation using only this information. They should be independent and
|
:class:`.info.SpectralInformation` using only this information. They should be independent and
|
||||||
self-contained.
|
self-contained.
|
||||||
|
|
||||||
Network elements MUST implement two attributes .uid and .name representing a
|
Network elements MUST implement two attributes .uid and .name representing a
|
||||||
unique identifier and a printable name.
|
unique identifier and a printable name.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from numpy import abs, arange, arcsinh, array, exp, divide, errstate
|
from numpy import abs, arange, array, exp, divide, errstate
|
||||||
from numpy import interp, log10, mean, pi, polyfit, polyval, sum
|
from numpy import interp, log10, mean, pi, polyfit, polyval, sum
|
||||||
from scipy.constants import c, h
|
from scipy.constants import c, h
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from gnpy.core.node import Node
|
from gnpy.core.node import Node
|
||||||
from gnpy.core.units import UNITS
|
from gnpy.core.units import UNITS
|
||||||
from gnpy.core.utils import lin2db, db2lin, itufs, snr_sum
|
from gnpy.core.utils import lin2db, db2lin, arrange_frequencies, snr_sum
|
||||||
|
from gnpy.core.science_utils import propagate_raman_fiber, _psi
|
||||||
|
|
||||||
class Transceiver(Node):
|
class Transceiver(Node):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -41,7 +42,6 @@ class Transceiver(Node):
|
|||||||
with errstate(divide='ignore'):
|
with errstate(divide='ignore'):
|
||||||
self.baud_rate = [c.baud_rate for c in spectral_info.carriers]
|
self.baud_rate = [c.baud_rate for c in spectral_info.carriers]
|
||||||
ratio_01nm = [lin2db(12.5e9/b_rate) for b_rate in self.baud_rate]
|
ratio_01nm = [lin2db(12.5e9/b_rate) for b_rate in self.baud_rate]
|
||||||
|
|
||||||
#set raw values to record original calculation, before update_snr()
|
#set raw values to record original calculation, before update_snr()
|
||||||
self.raw_osnr_ase = [lin2db(divide(c.power.signal, c.power.ase))
|
self.raw_osnr_ase = [lin2db(divide(c.power.signal, c.power.ase))
|
||||||
for c in spectral_info.carriers]
|
for c in spectral_info.carriers]
|
||||||
@@ -51,11 +51,14 @@ class Transceiver(Node):
|
|||||||
for c in spectral_info.carriers]
|
for c in spectral_info.carriers]
|
||||||
self.raw_snr = [lin2db(divide(c.power.signal, c.power.nli+c.power.ase))
|
self.raw_snr = [lin2db(divide(c.power.signal, c.power.nli+c.power.ase))
|
||||||
for c in spectral_info.carriers]
|
for c in spectral_info.carriers]
|
||||||
|
self.raw_snr_01nm = [snr - ratio for snr, ratio
|
||||||
|
in zip(self.raw_snr, ratio_01nm)]
|
||||||
|
|
||||||
self.osnr_ase = self.raw_osnr_ase
|
self.osnr_ase = self.raw_osnr_ase
|
||||||
self.osnr_ase_01nm = self.raw_osnr_ase_01nm
|
self.osnr_ase_01nm = self.raw_osnr_ase_01nm
|
||||||
self.osnr_nli = self.raw_osnr_nli
|
self.osnr_nli = self.raw_osnr_nli
|
||||||
self.snr = self.raw_snr
|
self.snr = self.raw_snr
|
||||||
|
self.snr_01nm = self.raw_snr_01nm
|
||||||
|
|
||||||
def update_snr(self, *args):
|
def update_snr(self, *args):
|
||||||
"""
|
"""
|
||||||
@@ -75,6 +78,8 @@ class Transceiver(Node):
|
|||||||
self.raw_snr, self.baud_rate))
|
self.raw_snr, self.baud_rate))
|
||||||
self.osnr_ase_01nm = list(map(lambda x:snr_sum(x,12.5e9,snr_added),
|
self.osnr_ase_01nm = list(map(lambda x:snr_sum(x,12.5e9,snr_added),
|
||||||
self.raw_osnr_ase_01nm))
|
self.raw_osnr_ase_01nm))
|
||||||
|
self.snr_01nm = list(map(lambda x:snr_sum(x,12.5e9,snr_added),
|
||||||
|
self.raw_snr_01nm))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
@@ -100,37 +105,42 @@ class Transceiver(Node):
|
|||||||
snr = round(mean(self.snr),2)
|
snr = round(mean(self.snr),2)
|
||||||
osnr_ase = round(mean(self.osnr_ase),2)
|
osnr_ase = round(mean(self.osnr_ase),2)
|
||||||
osnr_ase_01nm = round(mean(self.osnr_ase_01nm), 2)
|
osnr_ase_01nm = round(mean(self.osnr_ase_01nm), 2)
|
||||||
|
snr_01nm = round(mean(self.snr_01nm),2)
|
||||||
|
|
||||||
return '\n'.join([f'{type(self).__name__} {self.uid}',
|
return '\n'.join([f'{type(self).__name__} {self.uid}',
|
||||||
|
|
||||||
f' OSNR ASE (0.1nm): {osnr_ase_01nm:.2f}',
|
f' OSNR ASE (0.1nm, dB): {osnr_ase_01nm:.2f}',
|
||||||
f' OSNR ASE (signal bw): {osnr_ase:.2f}',
|
f' OSNR ASE (signal bw, dB): {osnr_ase:.2f}',
|
||||||
f' SNR total (signal bw): {snr:.2f}'])
|
f' SNR total (signal bw, dB): {snr:.2f}',
|
||||||
|
f' SNR total (0.1nm, dB): {snr_01nm:.2f}'])
|
||||||
|
|
||||||
def __call__(self, spectral_info):
|
def __call__(self, spectral_info):
|
||||||
self._calc_snr(spectral_info)
|
self._calc_snr(spectral_info)
|
||||||
return spectral_info
|
return spectral_info
|
||||||
|
|
||||||
RoadmParams = namedtuple('RoadmParams', 'loss')
|
RoadmParams = namedtuple('RoadmParams', 'target_pch_out_db add_drop_osnr restrictions per_degree_target_pch_out_db')
|
||||||
|
|
||||||
class Roadm(Node):
|
class Roadm(Node):
|
||||||
def __init__(self, *args, params=None, **kwargs):
|
def __init__(self, *args, params, **kwargs):
|
||||||
if params is None:
|
if 'per_degree_target_pch_out_db' not in params.keys():
|
||||||
# default loss value if not mentioned in loaded network json
|
params['per_degree_target_pch_out_db'] = []
|
||||||
params = {'loss':None}
|
|
||||||
super().__init__(*args, params=RoadmParams(**params), **kwargs)
|
super().__init__(*args, params=RoadmParams(**params), **kwargs)
|
||||||
self.loss = self.params.loss
|
self.loss = 0 #auto-design interest
|
||||||
self.target_pch_out_db = None #set in Networks.py by def set_roadm_loss
|
self.effective_loss = None
|
||||||
self.effective_pch_out_db = None
|
self.effective_pch_out_db = self.params.target_pch_out_db
|
||||||
self.effective_loss = None #set in self.propagate
|
|
||||||
self.passive = True
|
self.passive = True
|
||||||
|
self.restrictions = self.params.restrictions
|
||||||
|
self.per_degree_target_pch_out_db = self.params.per_degree_target_pch_out_db
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return {'uid' : self.uid,
|
return {'uid' : self.uid,
|
||||||
'type' : type(self).__name__,
|
'type' : type(self).__name__,
|
||||||
'params' : {'loss' : self.loss},
|
'params' : {
|
||||||
|
'target_pch_out_db' : self.effective_pch_out_db,
|
||||||
|
'restrictions' : self.restrictions,
|
||||||
|
'per_degree_target_pch_out_db': self.per_degree_target_pch_out_db
|
||||||
|
},
|
||||||
'metadata' : {
|
'metadata' : {
|
||||||
'location': self.metadata['location']._asdict()
|
'location': self.metadata['location']._asdict()
|
||||||
}
|
}
|
||||||
@@ -141,35 +151,45 @@ class Roadm(Node):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '\n'.join([f'{type(self).__name__} {self.uid}',
|
return '\n'.join([f'{type(self).__name__} {self.uid}',
|
||||||
f' loss (dB): {self.effective_loss:.2f}',
|
f' effective loss (dB): {self.effective_loss:.2f}',
|
||||||
f' pch out (dBm): {self.effective_pch_out_db!r}'])
|
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']
|
#pin_target and loss are read from eqpt_config.json['Roadm']
|
||||||
#all ingress channels in xpress are set to this power level
|
#all ingress channels in xpress are set to this power level
|
||||||
#but add channels are not, so we define an effective loss
|
#but add channels are not, so we define an effective loss
|
||||||
#in the case of add channels
|
#in the case of add channels
|
||||||
if self.target_pch_out_db:
|
if self.per_degree_target_pch_out_db:
|
||||||
self.effective_loss = pref.pi - self.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:
|
else:
|
||||||
self.effective_loss = self.loss
|
# if no per degree target power are defined, use the global one
|
||||||
self.effective_pch_out_db = pref.pi - self.effective_loss
|
temp = self.params.target_pch_out_db
|
||||||
attenuation = db2lin(self.effective_loss)
|
self.effective_pch_out_db = min(pref.p_spani, temp)
|
||||||
|
self.effective_loss = pref.p_spani - self.effective_pch_out_db
|
||||||
for carrier in carriers:
|
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.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) :
|
||||||
pwr = carrier.power
|
pwr = carrier.power
|
||||||
pwr = pwr._replace(signal=pwr.signal/attenuation,
|
pwr = pwr._replace( signal = pwr.signal/carrier_att,
|
||||||
nonlinear_interference=pwr.nli/attenuation,
|
nli = pwr.nli/carrier_att,
|
||||||
amplified_spontaneous_emission=pwr.ase/attenuation)
|
ase = pwr.ase/carrier_att)
|
||||||
yield carrier._replace(power=pwr)
|
yield carrier._replace(power=pwr)
|
||||||
|
|
||||||
def update_pref(self, pref):
|
def update_pref(self, pref):
|
||||||
return pref._replace(p_span0=pref.p0, p_spani=self.effective_pch_out_db)
|
return pref._replace(p_span0=pref.p_span0, p_spani=self.effective_pch_out_db)
|
||||||
|
|
||||||
def __call__(self, spectral_info):
|
def __call__(self, spectral_info, degree):
|
||||||
carriers = tuple(self.propagate(spectral_info.pref, *spectral_info.carriers))
|
carriers = tuple(self.propagate(spectral_info.pref, *spectral_info.carriers, degree=degree))
|
||||||
pref = self.update_pref(spectral_info.pref)
|
pref = self.update_pref(spectral_info.pref)
|
||||||
return spectral_info.update(carriers=carriers, pref=pref)
|
return spectral_info._replace(carriers=carriers, pref=pref)
|
||||||
|
|
||||||
FusedParams = namedtuple('FusedParams', 'loss')
|
FusedParams = namedtuple('FusedParams', 'loss')
|
||||||
|
|
||||||
@@ -186,6 +206,9 @@ class Fused(Node):
|
|||||||
def to_json(self):
|
def to_json(self):
|
||||||
return {'uid' : self.uid,
|
return {'uid' : self.uid,
|
||||||
'type' : type(self).__name__,
|
'type' : type(self).__name__,
|
||||||
|
'params' :{
|
||||||
|
'loss': self.loss
|
||||||
|
},
|
||||||
'metadata' : {
|
'metadata' : {
|
||||||
'location': self.metadata['location']._asdict()
|
'location': self.metadata['location']._asdict()
|
||||||
}
|
}
|
||||||
@@ -204,17 +227,17 @@ class Fused(Node):
|
|||||||
for carrier in carriers:
|
for carrier in carriers:
|
||||||
pwr = carrier.power
|
pwr = carrier.power
|
||||||
pwr = pwr._replace(signal=pwr.signal/attenuation,
|
pwr = pwr._replace(signal=pwr.signal/attenuation,
|
||||||
nonlinear_interference=pwr.nli/attenuation,
|
nli=pwr.nli/attenuation,
|
||||||
amplified_spontaneous_emission=pwr.ase/attenuation)
|
ase=pwr.ase/attenuation)
|
||||||
yield carrier._replace(power=pwr)
|
yield carrier._replace(power=pwr)
|
||||||
|
|
||||||
def update_pref(self, pref):
|
def update_pref(self, pref):
|
||||||
return pref._replace(p_span0=pref.p0, p_spani=pref.pi - self.loss)
|
return pref._replace(p_span0=pref.p_span0, p_spani=pref.p_spani - self.loss)
|
||||||
|
|
||||||
def __call__(self, spectral_info):
|
def __call__(self, spectral_info):
|
||||||
carriers = tuple(self.propagate(*spectral_info.carriers))
|
carriers = tuple(self.propagate(*spectral_info.carriers))
|
||||||
pref = self.update_pref(spectral_info.pref)
|
pref = self.update_pref(spectral_info.pref)
|
||||||
return spectral_info.update(carriers=carriers, pref=pref)
|
return spectral_info._replace(carriers=carriers, pref=pref)
|
||||||
|
|
||||||
FiberParams = namedtuple('FiberParams', 'type_variety length loss_coef length_units \
|
FiberParams = namedtuple('FiberParams', 'type_variety length loss_coef length_units \
|
||||||
att_in con_in con_out dispersion gamma')
|
att_in con_in con_out dispersion gamma')
|
||||||
@@ -283,12 +306,12 @@ class Fiber(Node):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def fiber_loss(self):
|
def fiber_loss(self):
|
||||||
# dB fiber loss, not including padding attenuator
|
"""Fiber loss in dB, not including padding attenuator"""
|
||||||
return self.loss_coef * self.length + self.con_in + self.con_out
|
return self.loss_coef * self.length + self.con_in + self.con_out
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def loss(self):
|
def loss(self):
|
||||||
#total loss incluiding padding att_in: useful for polymorphism with roadm loss
|
"""total loss including padding att_in: useful for polymorphism with roadm loss"""
|
||||||
return self.loss_coef * self.length + self.con_in + self.con_out + self.att_in
|
return self.loss_coef * self.length + self.con_in + self.con_out + self.att_in
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -313,16 +336,13 @@ class Fiber(Node):
|
|||||||
|
|
||||||
def carriers(self, loc, attr):
|
def carriers(self, loc, attr):
|
||||||
"""retrieve carriers information
|
"""retrieve carriers information
|
||||||
loc = (in, out) of the class element
|
|
||||||
attr = (ase, nli, signal, total) power information"""
|
:param loc: (in, out) of the class element
|
||||||
|
:param attr: (ase, nli, signal, total) power information
|
||||||
|
"""
|
||||||
if not (loc in ('in', 'out') and attr in ('nli', 'signal', 'total', 'ase')):
|
if not (loc in ('in', 'out') and attr in ('nli', 'signal', 'total', 'ase')):
|
||||||
yield None
|
yield None
|
||||||
return
|
return
|
||||||
power_dict = {
|
|
||||||
'nli': 'nonlinear_interference',
|
|
||||||
'ase': 'amplified_spontaneous_emission'
|
|
||||||
}
|
|
||||||
attr = power_dict.get(attr, attr)
|
|
||||||
loc_attr = 'carriers_'+loc
|
loc_attr = 'carriers_'+loc
|
||||||
for c in getattr(self, loc_attr) :
|
for c in getattr(self, loc_attr) :
|
||||||
if attr == 'total':
|
if attr == 'total':
|
||||||
@@ -330,46 +350,30 @@ class Fiber(Node):
|
|||||||
else:
|
else:
|
||||||
yield c.power._asdict().get(attr, None)
|
yield c.power._asdict().get(attr, None)
|
||||||
|
|
||||||
def beta2(self, ref_wavelength=None):
|
def beta2(self, ref_wavelength=1550e-9):
|
||||||
"""Returns beta2 from dispersion parameter.
|
"""Returns beta2 from dispersion parameter.
|
||||||
Dispersion is entered in ps/nm/km.
|
Dispersion is entered in ps/nm/km.
|
||||||
Disperion can be a numpy array or a single value. If a
|
Disperion can be a numpy array or a single value.
|
||||||
value ref_wavelength is not entered 1550e-9m will be assumed.
|
|
||||||
ref_wavelength can be a numpy array.
|
:param ref_wavelength: can be a numpy array; default: 1550nm
|
||||||
"""
|
"""
|
||||||
# TODO|jla: discuss beta2 as method or attribute
|
# TODO|jla: discuss beta2 as method or attribute
|
||||||
wl = 1550e-9 if ref_wavelength is None else ref_wavelength
|
|
||||||
D = abs(self.dispersion)
|
D = abs(self.dispersion)
|
||||||
b2 = (wl ** 2) * D / (2 * pi * c) # 10^21 scales [ps^2/km]
|
b2 = (ref_wavelength ** 2) * D / (2 * pi * c) # 10^21 scales [ps^2/km]
|
||||||
return b2 # s/Hz/m
|
return b2 # s/Hz/m
|
||||||
|
|
||||||
def dbkm_2_lin(self):
|
def dbkm_2_lin(self):
|
||||||
""" calculates the linear loss coefficient
|
"""calculates the linear loss coefficient"""
|
||||||
"""
|
# linear loss coefficient in dB/km^-1
|
||||||
# alpha_pcoef is linear loss coefficient in dB/km^-1
|
|
||||||
# alpha_acoef is linear loss field amplitude coefficient in m^-1
|
|
||||||
alpha_pcoef = self.loss_coef
|
alpha_pcoef = self.loss_coef
|
||||||
|
# linear loss field amplitude coefficient in m^-1
|
||||||
alpha_acoef = alpha_pcoef / (2 * 10 * log10(exp(1)))
|
alpha_acoef = alpha_pcoef / (2 * 10 * log10(exp(1)))
|
||||||
return alpha_pcoef, alpha_acoef
|
return alpha_pcoef, alpha_acoef
|
||||||
|
|
||||||
def _psi(self, carrier, interfering_carrier):
|
|
||||||
""" Calculates eq. 123 from arXiv:1209.0394.
|
|
||||||
"""
|
|
||||||
if carrier.num_chan == interfering_carrier.num_chan: # SCI
|
|
||||||
psi = arcsinh(0.5 * pi**2 * self.asymptotic_length
|
|
||||||
* abs(self.beta2()) * carrier.baud_rate**2)
|
|
||||||
else: # XCI
|
|
||||||
delta_f = carrier.freq - interfering_carrier.freq
|
|
||||||
psi = arcsinh(pi**2 * self.asymptotic_length * abs(self.beta2())
|
|
||||||
* carrier.baud_rate * (delta_f + 0.5 * interfering_carrier.baud_rate))
|
|
||||||
psi -= arcsinh(pi**2 * self.asymptotic_length * abs(self.beta2())
|
|
||||||
* carrier.baud_rate * (delta_f - 0.5 * interfering_carrier.baud_rate))
|
|
||||||
|
|
||||||
return psi
|
|
||||||
|
|
||||||
def _gn_analytic(self, carrier, *carriers):
|
def _gn_analytic(self, carrier, *carriers):
|
||||||
"""Computes the nonlinear interference power on a single carrier.
|
"""Computes the nonlinear interference power on a single carrier.
|
||||||
The method uses eq. 120 from arXiv:1209.0394.
|
The method uses eq. 120 from `arXiv:1209.0394 <https://arxiv.org/abs/1209.0394>`__.
|
||||||
|
|
||||||
:param carrier: the signal under analysis
|
:param carrier: the signal under analysis
|
||||||
:param carriers: the full WDM comb
|
:param carriers: the full WDM comb
|
||||||
:return: carrier_nli: the amount of nonlinear interference in W on the under analysis
|
:return: carrier_nli: the amount of nonlinear interference in W on the under analysis
|
||||||
@@ -377,7 +381,7 @@ class Fiber(Node):
|
|||||||
|
|
||||||
g_nli = 0
|
g_nli = 0
|
||||||
for interfering_carrier in carriers:
|
for interfering_carrier in carriers:
|
||||||
psi = self._psi(carrier, interfering_carrier)
|
psi = _psi(carrier, interfering_carrier, beta2=self.beta2(), asymptotic_length=self.asymptotic_length)
|
||||||
g_nli += (interfering_carrier.power.signal/interfering_carrier.baud_rate)**2 \
|
g_nli += (interfering_carrier.power.signal/interfering_carrier.baud_rate)**2 \
|
||||||
* (carrier.power.signal/carrier.baud_rate) * psi
|
* (carrier.power.signal/carrier.baud_rate) * psi
|
||||||
|
|
||||||
@@ -396,8 +400,8 @@ class Fiber(Node):
|
|||||||
for carrier in carriers:
|
for carrier in carriers:
|
||||||
pwr = carrier.power
|
pwr = carrier.power
|
||||||
pwr = pwr._replace(signal=pwr.signal/attenuation,
|
pwr = pwr._replace(signal=pwr.signal/attenuation,
|
||||||
nonlinear_interference=pwr.nli/attenuation,
|
nli=pwr.nli/attenuation,
|
||||||
amplified_spontaneous_emission=pwr.ase/attenuation)
|
ase=pwr.ase/attenuation)
|
||||||
carrier = carrier._replace(power=pwr)
|
carrier = carrier._replace(power=pwr)
|
||||||
chan.append(carrier)
|
chan.append(carrier)
|
||||||
|
|
||||||
@@ -409,20 +413,77 @@ class Fiber(Node):
|
|||||||
pwr = carrier.power
|
pwr = carrier.power
|
||||||
carrier_nli = self._gn_analytic(carrier, *carriers)
|
carrier_nli = self._gn_analytic(carrier, *carriers)
|
||||||
pwr = pwr._replace(signal=pwr.signal/self.lin_attenuation/attenuation,
|
pwr = pwr._replace(signal=pwr.signal/self.lin_attenuation/attenuation,
|
||||||
nonlinear_interference=(pwr.nli+carrier_nli)/self.lin_attenuation/attenuation,
|
nli=(pwr.nli+carrier_nli)/self.lin_attenuation/attenuation,
|
||||||
amplified_spontaneous_emission=pwr.ase/self.lin_attenuation/attenuation)
|
ase=pwr.ase/self.lin_attenuation/attenuation)
|
||||||
yield carrier._replace(power=pwr)
|
yield carrier._replace(power=pwr)
|
||||||
|
|
||||||
def update_pref(self, pref):
|
def update_pref(self, pref):
|
||||||
self.pch_out_db = round(pref.pi - self.loss, 2)
|
self.pch_out_db = round(pref.p_spani - self.loss, 2)
|
||||||
return pref._replace(p_span0=pref.p0, p_spani=self.pch_out_db)
|
return pref._replace(p_span0=pref.p_span0, p_spani=self.pch_out_db)
|
||||||
|
|
||||||
def __call__(self, spectral_info):
|
def __call__(self, spectral_info):
|
||||||
self.carriers_in = spectral_info.carriers
|
self.carriers_in = spectral_info.carriers
|
||||||
carriers = tuple(self.propagate(*spectral_info.carriers))
|
carriers = tuple(self.propagate(*spectral_info.carriers))
|
||||||
pref = self.update_pref(spectral_info.pref)
|
pref = self.update_pref(spectral_info.pref)
|
||||||
self.carriers_out = carriers
|
self.carriers_out = carriers
|
||||||
return spectral_info.update(carriers=carriers, pref=pref)
|
return spectral_info._replace(carriers=carriers, pref=pref)
|
||||||
|
|
||||||
|
RamanFiberParams = namedtuple('RamanFiberParams', 'type_variety length loss_coef length_units \
|
||||||
|
att_in con_in con_out dispersion gamma raman_efficiency')
|
||||||
|
|
||||||
|
class RamanFiber(Fiber):
|
||||||
|
def __init__(self, *args, params=None, **kwargs):
|
||||||
|
if params is None:
|
||||||
|
params = {}
|
||||||
|
if 'con_in' not in params:
|
||||||
|
# if not defined in the network json connector loss in/out
|
||||||
|
# the None value will be updated in network.py[build_network]
|
||||||
|
# with default values from eqpt_config.json[Spans]
|
||||||
|
params['con_in'] = None
|
||||||
|
params['con_out'] = None
|
||||||
|
if 'att_in' not in params:
|
||||||
|
#fixed attenuator for padding
|
||||||
|
params['att_in'] = 0
|
||||||
|
|
||||||
|
# TODO: can we re-use the Fiber constructor in a better way?
|
||||||
|
Node.__init__(self, *args, params=RamanFiberParams(**params), **kwargs)
|
||||||
|
self.type_variety = self.params.type_variety
|
||||||
|
self.length = self.params.length * UNITS[self.params.length_units] # in m
|
||||||
|
self.loss_coef = self.params.loss_coef * 1e-3 # lineic loss dB/m
|
||||||
|
self.lin_loss_coef = self.params.loss_coef / (20 * log10(exp(1)))
|
||||||
|
self.att_in = self.params.att_in
|
||||||
|
self.con_in = self.params.con_in
|
||||||
|
self.con_out = self.params.con_out
|
||||||
|
self.dispersion = self.params.dispersion # s/m/m
|
||||||
|
self.gamma = self.params.gamma # 1/W/m
|
||||||
|
self.pch_out_db = None
|
||||||
|
self.carriers_in = None
|
||||||
|
self.carriers_out = None
|
||||||
|
# TODO|jla: discuss factor 2 in the linear lineic attenuation
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sim_params(self):
|
||||||
|
return self._sim_params
|
||||||
|
|
||||||
|
@sim_params.setter
|
||||||
|
def sim_params(self, sim_params=None):
|
||||||
|
self._sim_params = sim_params
|
||||||
|
|
||||||
|
def update_pref(self, pref, *carriers):
|
||||||
|
pch_out_db = lin2db(mean([carrier.power.signal for carrier in carriers])) + 30
|
||||||
|
self.pch_out_db = round(pch_out_db, 2)
|
||||||
|
return pref._replace(p_span0=pref.p_span0, p_spani=self.pch_out_db)
|
||||||
|
|
||||||
|
def __call__(self, spectral_info):
|
||||||
|
self.carriers_in = spectral_info.carriers
|
||||||
|
carriers = tuple(self.propagate(*spectral_info.carriers))
|
||||||
|
pref = self.update_pref(spectral_info.pref, *carriers)
|
||||||
|
self.carriers_out = carriers
|
||||||
|
return spectral_info._replace(carriers=carriers, pref=pref)
|
||||||
|
|
||||||
|
def propagate(self, *carriers):
|
||||||
|
for propagated_carrier in propagate_raman_fiber(self, *carriers):
|
||||||
|
yield propagated_carrier
|
||||||
|
|
||||||
class EdfaParams:
|
class EdfaParams:
|
||||||
def __init__(self, **params):
|
def __init__(self, **params):
|
||||||
@@ -430,16 +491,16 @@ class EdfaParams:
|
|||||||
if params == {}:
|
if params == {}:
|
||||||
self.type_variety = ''
|
self.type_variety = ''
|
||||||
self.type_def = ''
|
self.type_def = ''
|
||||||
self.gain_flatmax = 0
|
# self.gain_flatmax = 0
|
||||||
self.gain_min = 0
|
# self.gain_min = 0
|
||||||
self.p_max = 0
|
# self.p_max = 0
|
||||||
self.nf_model = None
|
# self.nf_model = None
|
||||||
self.nf_fit_coeff = None
|
# self.nf_fit_coeff = None
|
||||||
self.nf_ripple = None
|
# self.nf_ripple = None
|
||||||
self.dgt = None
|
# self.dgt = None
|
||||||
self.gain_ripple = None
|
# self.gain_ripple = None
|
||||||
self.out_voa_auto = False
|
# self.out_voa_auto = False
|
||||||
self.allowed_for_design = None
|
# self.allowed_for_design = None
|
||||||
|
|
||||||
def update_params(self, kwargs):
|
def update_params(self, kwargs):
|
||||||
for k,v in kwargs.items() :
|
for k,v in kwargs.items() :
|
||||||
@@ -447,22 +508,33 @@ class EdfaParams:
|
|||||||
if isinstance(v, dict) else v)
|
if isinstance(v, dict) else v)
|
||||||
|
|
||||||
class EdfaOperational:
|
class EdfaOperational:
|
||||||
def __init__(self, gain_target, tilt_target, out_voa=None):
|
default_values = \
|
||||||
self.gain_target = gain_target
|
{
|
||||||
self.tilt_target = tilt_target
|
'gain_target': None,
|
||||||
self.out_voa = out_voa
|
'delta_p': None,
|
||||||
|
'out_voa': None,
|
||||||
|
'tilt_target': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **operational):
|
||||||
|
self.update_attr(operational)
|
||||||
|
|
||||||
|
def update_attr(self, kwargs):
|
||||||
|
clean_kwargs = {k:v for k,v in kwargs.items() if v !=''}
|
||||||
|
for k,v in self.default_values.items():
|
||||||
|
setattr(self, k, clean_kwargs.get(k,v))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (f'{type(self).__name__}('
|
return (f'{type(self).__name__}('
|
||||||
f'gain_target={self.gain_target!r}, '
|
f'gain_target={self.gain_target!r}, '
|
||||||
f'tilt_target={self.tilt_target!r})')
|
f'tilt_target={self.tilt_target!r})')
|
||||||
|
|
||||||
class Edfa(Node):
|
class Edfa(Node):
|
||||||
def __init__(self, *args, params={}, operational={}, **kwargs):
|
def __init__(self, *args, params=None, operational=None, **kwargs):
|
||||||
#TBC is this useful? put in comment for now:
|
if params is None:
|
||||||
#if params is None:
|
params = {}
|
||||||
# params = {}
|
if operational is None:
|
||||||
#if operational is None:
|
operational = {}
|
||||||
# operational = {}
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
*args,
|
*args,
|
||||||
params=EdfaParams(**params),
|
params=EdfaParams(**params),
|
||||||
@@ -479,14 +551,16 @@ class Edfa(Node):
|
|||||||
self.pin_db = None
|
self.pin_db = None
|
||||||
self.nch = None
|
self.nch = None
|
||||||
self.pout_db = None
|
self.pout_db = None
|
||||||
self.dp_db = None #delta P with Pref (power swwep) in power mode
|
|
||||||
self.target_pch_out_db = None
|
self.target_pch_out_db = None
|
||||||
self.effective_pch_out_db = None
|
self.effective_pch_out_db = None
|
||||||
self.passive = False
|
self.passive = False
|
||||||
self.effective_gain = self.operational.gain_target
|
|
||||||
self.att_in = None
|
self.att_in = None
|
||||||
self.carriers_in = None
|
self.carriers_in = None
|
||||||
self.carriers_out = None
|
self.carriers_out = None
|
||||||
|
self.effective_gain = self.operational.gain_target
|
||||||
|
self.delta_p = self.operational.delta_p #delta P with Pref (power swwep) in power mode
|
||||||
|
self.tilt_target = self.operational.tilt_target
|
||||||
|
self.out_voa = self.operational.out_voa
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
@@ -494,9 +568,10 @@ class Edfa(Node):
|
|||||||
'type' : type(self).__name__,
|
'type' : type(self).__name__,
|
||||||
'type_variety' : self.params.type_variety,
|
'type_variety' : self.params.type_variety,
|
||||||
'operational' : {
|
'operational' : {
|
||||||
'gain_target' : self.operational.gain_target,
|
'gain_target' : self.effective_gain,
|
||||||
'tilt_target' : self.operational.tilt_target,
|
'delta_p' : self.delta_p,
|
||||||
'out_voa' : self.operational.out_voa
|
'tilt_target' : self.tilt_target,
|
||||||
|
'out_voa' : self.out_voa
|
||||||
},
|
},
|
||||||
'metadata' : {
|
'metadata' : {
|
||||||
'location': self.metadata['location']._asdict()
|
'location': self.metadata['location']._asdict()
|
||||||
@@ -505,7 +580,7 @@ class Edfa(Node):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (f'{type(self).__name__}(uid={self.uid!r}, '
|
return (f'{type(self).__name__}(uid={self.uid!r}, '
|
||||||
f'type_variety={self.params.type_variety!r}'
|
f'type_variety={self.params.type_variety!r}, '
|
||||||
f'interpol_dgt={self.interpol_dgt!r}, '
|
f'interpol_dgt={self.interpol_dgt!r}, '
|
||||||
f'interpol_gain_ripple={self.interpol_gain_ripple!r}, '
|
f'interpol_gain_ripple={self.interpol_gain_ripple!r}, '
|
||||||
f'interpol_nf_ripple={self.interpol_nf_ripple!r}, '
|
f'interpol_nf_ripple={self.interpol_nf_ripple!r}, '
|
||||||
@@ -528,23 +603,20 @@ class Edfa(Node):
|
|||||||
f' pad att_in (dB): {self.att_in:.2f}',
|
f' pad att_in (dB): {self.att_in:.2f}',
|
||||||
f' Power In (dBm): {self.pin_db:.2f}',
|
f' Power In (dBm): {self.pin_db:.2f}',
|
||||||
f' Power Out (dBm): {self.pout_db:.2f}',
|
f' Power Out (dBm): {self.pout_db:.2f}',
|
||||||
f' Delta_P (dB): {self.dp_db!r}',
|
f' Delta_P (dB): {self.delta_p!r}',
|
||||||
f' target pch (dBm): {self.target_pch_out_db!r}',
|
f' target pch (dBm): {self.target_pch_out_db!r}',
|
||||||
f' effective pch (dBm): {self.effective_pch_out_db!r}',
|
f' effective pch (dBm): {self.effective_pch_out_db!r}',
|
||||||
f' output VOA (dB): {self.operational.out_voa:.2f}'])
|
f' output VOA (dB): {self.out_voa:.2f}'])
|
||||||
|
|
||||||
def carriers(self, loc, attr):
|
def carriers(self, loc, attr):
|
||||||
"""retrieve carriers information
|
"""retrieve carriers information
|
||||||
loc = (in, out) of the class element
|
|
||||||
attr = (ase, nli, signal, total) power information"""
|
:param loc: (in, out) of the class element
|
||||||
|
:param attr: (ase, nli, signal, total) power information
|
||||||
|
"""
|
||||||
if not (loc in ('in', 'out') and attr in ('nli', 'signal', 'total', 'ase')):
|
if not (loc in ('in', 'out') and attr in ('nli', 'signal', 'total', 'ase')):
|
||||||
yield None
|
yield None
|
||||||
return
|
return
|
||||||
power_dict = {
|
|
||||||
'nli': 'nonlinear_interference',
|
|
||||||
'ase': 'amplified_spontaneous_emission'
|
|
||||||
}
|
|
||||||
attr = power_dict.get(attr, attr)
|
|
||||||
loc_attr = 'carriers_'+loc
|
loc_attr = 'carriers_'+loc
|
||||||
for c in getattr(self, loc_attr) :
|
for c in getattr(self, loc_attr) :
|
||||||
if attr == 'total':
|
if attr == 'total':
|
||||||
@@ -553,66 +625,103 @@ class Edfa(Node):
|
|||||||
yield c.power._asdict().get(attr, None)
|
yield c.power._asdict().get(attr, None)
|
||||||
|
|
||||||
def interpol_params(self, frequencies, pin, baud_rates, pref):
|
def interpol_params(self, frequencies, pin, baud_rates, pref):
|
||||||
"""interpolate SI channel frequencies with the edfa dgt and gain_ripple frquencies from json
|
"""interpolate SI channel frequencies with the edfa dgt and gain_ripple frquencies from JSON
|
||||||
set the edfa class __init__ None parameters :
|
set the edfa class __init__ None parameters :
|
||||||
self.channel_freq, self.nf, self.interpol_dgt and self.interpol_gain_ripple
|
self.channel_freq, self.nf, self.interpol_dgt and self.interpol_gain_ripple
|
||||||
"""
|
"""
|
||||||
# TODO|jla: read amplifier actual frequencies from additional params in json
|
# TODO|jla: read amplifier actual frequencies from additional params in json
|
||||||
amplifier_freq = itufs(0.05) * 1e12 # Hz
|
amplifier_freq = arrange_frequencies(len(self.params.dgt), self.params.f_min, self.params.f_max) # Hz
|
||||||
self.channel_freq = frequencies
|
self.channel_freq = frequencies
|
||||||
self.interpol_dgt = interp(self.channel_freq, amplifier_freq, self.params.dgt)
|
self.interpol_dgt = interp(self.channel_freq, amplifier_freq, self.params.dgt)
|
||||||
|
|
||||||
self.interpol_gain_ripple = interp(self.channel_freq, amplifier_freq, self.params.gain_ripple)
|
self.interpol_gain_ripple = interp(self.channel_freq, amplifier_freq, self.params.gain_ripple)
|
||||||
self.interpol_nf_ripple =interp(self.channel_freq, amplifier_freq, self.params.nf_ripple)
|
self.interpol_nf_ripple =interp(self.channel_freq, amplifier_freq, self.params.nf_ripple)
|
||||||
|
|
||||||
self.nch = frequencies.size
|
self.nch = frequencies.size
|
||||||
self.pin_db = lin2db(sum(pin*1e3))
|
self.pin_db = lin2db(sum(pin*1e3))
|
||||||
|
|
||||||
"""in power mode: dp_db is defined and can be used to calculate the power target
|
"""in power mode: delta_p is defined and can be used to calculate the power target
|
||||||
This power target is used calculate the amplifier gain"""
|
This power target is used calculate the amplifier gain"""
|
||||||
if self.dp_db is not None:
|
if self.delta_p is not None:
|
||||||
self.target_pch_out_db = round(self.dp_db + pref.p0, 2)
|
self.target_pch_out_db = round(self.delta_p + pref.p_span0, 2)
|
||||||
self.effective_gain = self.target_pch_out_db - pref.pi
|
self.effective_gain = self.target_pch_out_db - pref.p_spani
|
||||||
else:
|
|
||||||
self.effective_gain = self.operational.gain_target
|
"""check power saturation and correct effective gain & power accordingly:"""
|
||||||
|
self.effective_gain = min(
|
||||||
|
self.effective_gain,
|
||||||
|
self.params.p_max - (pref.p_spani + pref.neq_ch)
|
||||||
|
)
|
||||||
|
#print(self.uid, self.effective_gain, self.operational.gain_target)
|
||||||
|
self.effective_pch_out_db = round(pref.p_spani + self.effective_gain, 2)
|
||||||
|
|
||||||
"""check power saturation and correct target_gain accordingly:"""
|
"""check power saturation and correct target_gain accordingly:"""
|
||||||
self.effective_gain = min(self.effective_gain, self.params.p_max - self.pin_db)
|
#print(self.uid, self.effective_gain, self.pin_db, pref.p_spani)
|
||||||
self.effective_pch_out_db = round(pref.pi + self.effective_gain, 2)
|
|
||||||
|
|
||||||
self.nf = self._calc_nf()
|
self.nf = self._calc_nf()
|
||||||
self.gprofile = self._gain_profile(pin)
|
self.gprofile = self._gain_profile(pin)
|
||||||
|
|
||||||
pout = (pin + self.noise_profile(baud_rates))*db2lin(self.gprofile)
|
pout = (pin + self.noise_profile(baud_rates))*db2lin(self.gprofile)
|
||||||
self.pout_db = lin2db(sum(pout*1e3))
|
self.pout_db = lin2db(sum(pout*1e3))
|
||||||
self.operational.gain_target = self.effective_gain
|
|
||||||
# ase & nli are only calculated in signal bandwidth
|
# ase & nli are only calculated in signal bandwidth
|
||||||
# pout_db is not the absolute full output power (negligible if sufficient channels)
|
# pout_db is not the absolute full output power (negligible if sufficient channels)
|
||||||
|
|
||||||
|
def _nf(self, type_def, nf_model, nf_fit_coeff, gain_min, gain_flatmax, gain_target):
|
||||||
|
#if hybrid raman, use edfa_gain_flatmax attribute, else use gain_flatmax
|
||||||
|
#gain_flatmax = getattr(params, 'edfa_gain_flatmax', params.gain_flatmax)
|
||||||
|
pad = max(gain_min - gain_target, 0)
|
||||||
|
gain_target += pad
|
||||||
|
dg = max(gain_flatmax - gain_target, 0)
|
||||||
|
if type_def == 'variable_gain':
|
||||||
|
g1a = gain_target - nf_model.delta_p - dg
|
||||||
|
nf_avg = lin2db(db2lin(nf_model.nf1) + db2lin(nf_model.nf2)/db2lin(g1a))
|
||||||
|
elif type_def == 'fixed_gain':
|
||||||
|
nf_avg = nf_model.nf0
|
||||||
|
elif type_def == 'openroadm':
|
||||||
|
pin_ch = self.pin_db - lin2db(self.nch)
|
||||||
|
# model OSNR = f(Pin)
|
||||||
|
nf_avg = pin_ch - polyval(nf_model.nf_coef, pin_ch) + 58
|
||||||
|
elif type_def == 'advanced_model':
|
||||||
|
nf_avg = polyval(nf_fit_coeff, -dg)
|
||||||
|
else:
|
||||||
|
assert False, "Unrecognized amplifier type, this should have been checked by the JSON loader"
|
||||||
|
return nf_avg+pad, pad
|
||||||
|
|
||||||
def _calc_nf(self, avg = False):
|
def _calc_nf(self, avg = False):
|
||||||
"""nf calculation based on 2 models: self.params.nf_model.enabled from json import:
|
"""nf calculation based on 2 models: self.params.nf_model.enabled from json import:
|
||||||
True => 2 stages amp modelling based on precalculated nf1, nf2 and delta_p in build_OA_json
|
True => 2 stages amp modelling based on precalculated nf1, nf2 and delta_p in build_OA_json
|
||||||
False => polynomial fit based on self.params.nf_fit_coeff"""
|
False => polynomial fit based on self.params.nf_fit_coeff"""
|
||||||
# TODO|jla: TBD alarm rising or input VOA padding in case
|
|
||||||
# gain_min > gain_target TBD:
|
# gain_min > gain_target TBD:
|
||||||
pad = max(self.params.gain_min - self.effective_gain, 0)
|
if self.params.type_def == 'dual_stage':
|
||||||
self.att_in = pad
|
g1 = self.params.preamp_gain_flatmax
|
||||||
gain_target = self.effective_gain + pad
|
g2 = self.effective_gain - g1
|
||||||
dg = max(self.params.gain_flatmax - gain_target, 0)
|
nf1_avg, pad = self._nf( self.params.preamp_type_def,
|
||||||
if self.params.type_def == 'variable_gain':
|
self.params.preamp_nf_model,
|
||||||
g1a = gain_target - self.params.nf_model.delta_p - dg
|
self.params.preamp_nf_fit_coeff,
|
||||||
nf_avg = lin2db(db2lin(self.params.nf_model.nf1) + db2lin(self.params.nf_model.nf2)/db2lin(g1a))
|
self.params.preamp_gain_min,
|
||||||
elif self.params.type_def == 'fixed_gain':
|
self.params.preamp_gain_flatmax,
|
||||||
nf_avg = self.params.nf_model.nf0
|
g1)
|
||||||
elif self.params.type_def == 'openroadm':
|
#no padding expected for the 1stage because g1 = gain_max
|
||||||
pin_ch = self.pin_db - lin2db(self.nch)
|
nf2_avg, pad = self._nf( self.params.booster_type_def,
|
||||||
# model OSNR = f(Pin)
|
self.params.booster_nf_model,
|
||||||
nf_avg = pin_ch - polyval(self.params.nf_model.nf_coef, pin_ch) + 58
|
self.params.booster_nf_fit_coeff,
|
||||||
|
self.params.booster_gain_min,
|
||||||
|
self.params.booster_gain_flatmax,
|
||||||
|
g2)
|
||||||
|
nf_avg = lin2db(db2lin(nf1_avg) + db2lin(nf2_avg-g1))
|
||||||
|
#no padding expected for the 1stage because g1 = gain_max
|
||||||
|
pad = 0
|
||||||
else:
|
else:
|
||||||
nf_avg = polyval(self.params.nf_fit_coeff, -dg)
|
nf_avg, pad = self._nf( self.params.type_def,
|
||||||
|
self.params.nf_model,
|
||||||
|
self.params.nf_fit_coeff,
|
||||||
|
self.params.gain_min,
|
||||||
|
self.params.gain_flatmax,
|
||||||
|
self.effective_gain)
|
||||||
|
|
||||||
|
self.att_in = pad # not used to attenuate carriers, only used in _repr_ and _str_
|
||||||
if avg:
|
if avg:
|
||||||
return nf_avg + pad
|
return nf_avg
|
||||||
else:
|
else:
|
||||||
return self.interpol_nf_ripple + nf_avg + pad # input VOA = 1 for 1 NF degradation
|
return self.interpol_nf_ripple + nf_avg # input VOA = 1 for 1 NF degradation
|
||||||
|
|
||||||
def noise_profile(self, df):
|
def noise_profile(self, df):
|
||||||
"""noise_profile(bw) computes amplifier ase (W) in signal bw (Hz)
|
"""noise_profile(bw) computes amplifier ase (W) in signal bw (Hz)
|
||||||
@@ -705,7 +814,7 @@ class Edfa(Node):
|
|||||||
|
|
||||||
# Calculate the target slope - currently assumes equal spaced channels
|
# Calculate the target slope - currently assumes equal spaced channels
|
||||||
# TODO|jla: support arbitrary channel spacing
|
# TODO|jla: support arbitrary channel spacing
|
||||||
targ_slope = self.operational.tilt_target / (len(nb_channel) - 1)
|
targ_slope = self.tilt_target / (len(nb_channel) - 1)
|
||||||
|
|
||||||
# first estimate of DGT scaling
|
# first estimate of DGT scaling
|
||||||
if abs(dgt_slope) > 0.001: # check for zero value due to flat dgt
|
if abs(dgt_slope) > 0.001: # check for zero value due to flat dgt
|
||||||
@@ -770,7 +879,7 @@ class Edfa(Node):
|
|||||||
return g1st - voa + array(self.interpol_dgt) * dgts3
|
return g1st - voa + array(self.interpol_dgt) * dgts3
|
||||||
|
|
||||||
def propagate(self, pref, *carriers):
|
def propagate(self, pref, *carriers):
|
||||||
"""add ase noise to the propagating carriers of SpectralInformation"""
|
"""add ASE noise to the propagating carriers of :class:`.info.SpectralInformation`"""
|
||||||
pin = array([c.power.signal+c.power.nli+c.power.ase for c in carriers]) # pin in W
|
pin = array([c.power.signal+c.power.nli+c.power.ase for c in carriers]) # pin in W
|
||||||
freq = array([c.frequency for c in carriers])
|
freq = array([c.frequency for c in carriers])
|
||||||
brate = array([c.baud_rate for c in carriers])
|
brate = array([c.baud_rate for c in carriers])
|
||||||
@@ -779,22 +888,22 @@ class Edfa(Node):
|
|||||||
|
|
||||||
gains = db2lin(self.gprofile)
|
gains = db2lin(self.gprofile)
|
||||||
carrier_ases = self.noise_profile(brate)
|
carrier_ases = self.noise_profile(brate)
|
||||||
att = db2lin(self.operational.out_voa)
|
att = db2lin(self.out_voa)
|
||||||
|
|
||||||
for gain, carrier_ase, carrier in zip(gains, carrier_ases, carriers):
|
for gain, carrier_ase, carrier in zip(gains, carrier_ases, carriers):
|
||||||
pwr = carrier.power
|
pwr = carrier.power
|
||||||
pwr = pwr._replace(signal=pwr.signal*gain/att,
|
pwr = pwr._replace(signal=pwr.signal*gain/att,
|
||||||
nonlinear_interference=pwr.nli*gain/att,
|
nli=pwr.nli*gain/att,
|
||||||
amplified_spontaneous_emission=(pwr.ase+carrier_ase)*gain/att)
|
ase=(pwr.ase+carrier_ase)*gain/att)
|
||||||
yield carrier._replace(power=pwr)
|
yield carrier._replace(power=pwr)
|
||||||
|
|
||||||
def update_pref(self, pref):
|
def update_pref(self, pref):
|
||||||
return pref._replace(p_span0=pref.p0,
|
return pref._replace(p_span0=pref.p_span0,
|
||||||
p_spani=pref.pi + self.effective_gain - self.operational.out_voa)
|
p_spani=pref.p_spani + self.effective_gain - self.out_voa)
|
||||||
|
|
||||||
def __call__(self, spectral_info):
|
def __call__(self, spectral_info):
|
||||||
self.carriers_in = spectral_info.carriers
|
self.carriers_in = spectral_info.carriers
|
||||||
carriers = tuple(self.propagate(spectral_info.pref, *spectral_info.carriers))
|
carriers = tuple(self.propagate(spectral_info.pref, *spectral_info.carriers))
|
||||||
pref = self.update_pref(spectral_info.pref)
|
pref = self.update_pref(spectral_info.pref)
|
||||||
self.carriers_out = carriers
|
self.carriers_out = carriers
|
||||||
return spectral_info.update(carriers=carriers, pref=pref)
|
return spectral_info._replace(carriers=carriers, pref=pref)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ This module contains functionality for specifying equipment.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from numpy import clip, polyval
|
from numpy import clip, polyval
|
||||||
from sys import exit
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from math import isclose
|
from math import isclose
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -17,64 +16,169 @@ from json import load
|
|||||||
from gnpy.core.utils import lin2db, db2lin, load_json
|
from gnpy.core.utils import lin2db, db2lin, load_json
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from gnpy.core.elements import Edfa
|
from gnpy.core.elements import Edfa
|
||||||
|
from gnpy.core.exceptions import EquipmentConfigError
|
||||||
|
import time
|
||||||
|
|
||||||
Model_vg = namedtuple('Model_vg', 'nf1 nf2 delta_p')
|
Model_vg = namedtuple('Model_vg', 'nf1 nf2 delta_p')
|
||||||
Model_fg = namedtuple('Model_fg', 'nf0')
|
Model_fg = namedtuple('Model_fg', 'nf0')
|
||||||
Model_openroadm = namedtuple('Model_openroadm', 'nf_coef')
|
Model_openroadm = namedtuple('Model_openroadm', 'nf_coef')
|
||||||
Fiber = namedtuple('Fiber', 'type_variety dispersion gamma')
|
Model_hybrid = namedtuple('Model_hybrid', 'nf_ram gain_ram edfa_variety')
|
||||||
Spans = namedtuple('Spans', 'power_mode delta_power_range_db max_length length_units \
|
Model_dual_stage = namedtuple('Model_dual_stage', 'preamp_variety booster_variety')
|
||||||
max_loss padding EOL con_in con_out')
|
|
||||||
Transceiver = namedtuple('Transceiver', 'type_variety frequency mode')
|
class common:
|
||||||
Roadms = namedtuple('Roadms', 'gain_mode_default_loss power_mode_pout_target add_drop_osnr')
|
def update_attr(self, default_values, kwargs, name):
|
||||||
SI = namedtuple('SI', 'f_min f_max baud_rate spacing roll_off \
|
clean_kwargs = {k:v for k, v in kwargs.items() if v != ''}
|
||||||
power_dbm power_range_db tx_osnr sys_margins')
|
for k, v in default_values.items():
|
||||||
AmpBase = namedtuple(
|
setattr(self, k, clean_kwargs.get(k, v))
|
||||||
'AmpBase',
|
if k not in clean_kwargs and name != 'Amp':
|
||||||
'type_variety type_def gain_flatmax gain_min p_max'
|
print(f'\x1b[1;31;40m'+
|
||||||
' nf_model nf_fit_coeff nf_ripple dgt gain_ripple out_voa_auto allowed_for_design')
|
f'\n WARNING missing {k} attribute in eqpt_config.json[{name}]'+
|
||||||
class Amp(AmpBase):
|
f'\n default value is {k} = {v}'+
|
||||||
def __new__(cls,
|
f'\x1b[0m')
|
||||||
type_variety, type_def, gain_flatmax, gain_min, p_max, nf_model=None,
|
time.sleep(1)
|
||||||
nf_fit_coeff=None, nf_ripple=None, dgt=None, gain_ripple=None,
|
|
||||||
out_voa_auto=False, allowed_for_design=True):
|
class SI(common):
|
||||||
return super().__new__(cls,
|
default_values =\
|
||||||
type_variety, type_def, gain_flatmax, gain_min, p_max,
|
{
|
||||||
nf_model, nf_fit_coeff, nf_ripple, dgt, gain_ripple,
|
"f_min": 191.35e12,
|
||||||
out_voa_auto, allowed_for_design)
|
"f_max": 196.1e12,
|
||||||
|
"baud_rate": 32e9,
|
||||||
|
"spacing": 50e9,
|
||||||
|
"power_dbm": 0,
|
||||||
|
"power_range_db": [0, 0, 0.5],
|
||||||
|
"roll_off": 0.15,
|
||||||
|
"tx_osnr": 45,
|
||||||
|
"sys_margins": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'SI')
|
||||||
|
|
||||||
|
class Span(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'power_mode': True,
|
||||||
|
'delta_power_range_db': None,
|
||||||
|
'max_fiber_lineic_loss_for_raman': 0.25,
|
||||||
|
'target_extended_gain': 2.5,
|
||||||
|
'max_length': 150,
|
||||||
|
'length_units': 'km',
|
||||||
|
'max_loss': None,
|
||||||
|
'padding': 10,
|
||||||
|
'EOL': 0,
|
||||||
|
'con_in': 0,
|
||||||
|
'con_out': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Span')
|
||||||
|
|
||||||
|
class Roadm(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'target_pch_out_db': -17,
|
||||||
|
'add_drop_osnr': 100,
|
||||||
|
'restrictions': {
|
||||||
|
'preamp_variety_list':[],
|
||||||
|
'booster_variety_list':[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Roadm')
|
||||||
|
|
||||||
|
class Transceiver(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'type_variety': None,
|
||||||
|
'frequency': None,
|
||||||
|
'mode': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Transceiver')
|
||||||
|
|
||||||
|
class Fiber(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'type_variety': '',
|
||||||
|
'dispersion': None,
|
||||||
|
'gamma': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Fiber')
|
||||||
|
|
||||||
|
class RamanFiber(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'type_variety': '',
|
||||||
|
'dispersion': None,
|
||||||
|
'gamma': 0,
|
||||||
|
'raman_efficiency': None
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'RamanFiber')
|
||||||
|
for param in ('cr', 'frequency_offset'):
|
||||||
|
if param not in self.raman_efficiency:
|
||||||
|
raise EquipmentConfigError(f'RamanFiber.raman_efficiency: missing "{param}" parameter')
|
||||||
|
if self.raman_efficiency['frequency_offset'] != sorted(self.raman_efficiency['frequency_offset']):
|
||||||
|
raise EquipmentConfigError(f'RamanFiber.raman_efficiency.frequency_offset is not sorted')
|
||||||
|
|
||||||
|
class Amp(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'f_min': 191.35e12,
|
||||||
|
'f_max': 196.1e12,
|
||||||
|
'type_variety': '',
|
||||||
|
'type_def': '',
|
||||||
|
'gain_flatmax': None,
|
||||||
|
'gain_min': None,
|
||||||
|
'p_max': None,
|
||||||
|
'nf_model': None,
|
||||||
|
'dual_stage_model': None,
|
||||||
|
'nf_fit_coeff': None,
|
||||||
|
'nf_ripple': None,
|
||||||
|
'dgt': None,
|
||||||
|
'gain_ripple': None,
|
||||||
|
'out_voa_auto': False,
|
||||||
|
'allowed_for_design': False,
|
||||||
|
'raman': False
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Amp')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_advanced_json(cls, filename, **kwargs):
|
def from_json(cls, filename, **kwargs):
|
||||||
with open(filename, encoding='utf-8') as f:
|
config = Path(filename).parent / 'default_edfa_config.json'
|
||||||
json_data = load(f)
|
|
||||||
return cls(**{**kwargs, **json_data, 'type_def':None, 'nf_model':None})
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_default_json(cls, filename, **kwargs):
|
|
||||||
with open(filename, encoding='utf-8') as f:
|
|
||||||
json_data = load(f)
|
|
||||||
type_variety = kwargs['type_variety']
|
type_variety = kwargs['type_variety']
|
||||||
type_def = kwargs.get('type_def', 'variable_gain') # default compatibility with older json eqpt files
|
type_def = kwargs.get('type_def', 'variable_gain') # default compatibility with older json eqpt files
|
||||||
nf_def = None
|
nf_def = None
|
||||||
|
dual_stage_def = None
|
||||||
|
|
||||||
if type_def == 'fixed_gain':
|
if type_def == 'fixed_gain':
|
||||||
try:
|
try:
|
||||||
nf0 = kwargs.pop('nf0')
|
nf0 = kwargs.pop('nf0')
|
||||||
except KeyError: #nf0 is expected for a fixed gain amp
|
except KeyError: #nf0 is expected for a fixed gain amp
|
||||||
print(f'missing nf0 value input for amplifier: {type_variety} in eqpt_config.json')
|
raise EquipmentConfigError(f'missing nf0 value input for amplifier: {type_variety} in equipment config')
|
||||||
exit()
|
for k in ('nf_min', 'nf_max'):
|
||||||
try: #remove all remaining nf inputs
|
try:
|
||||||
del kwargs['nf_min']
|
del kwargs[k]
|
||||||
del kwargs['nf_max']
|
except KeyError:
|
||||||
except KeyError: pass #nf_min and nf_max are not needed for fixed gain amp
|
pass
|
||||||
nf_def = Model_fg(nf0)
|
nf_def = Model_fg(nf0)
|
||||||
|
elif type_def == 'advanced_model':
|
||||||
|
config = Path(filename).parent / kwargs.pop('advanced_config_from_json')
|
||||||
elif type_def == 'variable_gain':
|
elif type_def == 'variable_gain':
|
||||||
gain_min, gain_max = kwargs['gain_min'], kwargs['gain_flatmax']
|
gain_min, gain_max = kwargs['gain_min'], kwargs['gain_flatmax']
|
||||||
try: #nf_min and nf_max are expected for a variable gain amp
|
try: #nf_min and nf_max are expected for a variable gain amp
|
||||||
nf_min = kwargs.pop('nf_min')
|
nf_min = kwargs.pop('nf_min')
|
||||||
nf_max = kwargs.pop('nf_max')
|
nf_max = kwargs.pop('nf_max')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print(f'missing nf_min/max value input for amplifier: {type_variety} in eqpt_config.json')
|
raise EquipmentConfigError(f'missing nf_min or nf_max value input for amplifier: {type_variety} in equipment config')
|
||||||
exit()
|
|
||||||
try: #remove all remaining nf inputs
|
try: #remove all remaining nf inputs
|
||||||
del kwargs['nf0']
|
del kwargs['nf0']
|
||||||
except KeyError: pass #nf0 is not needed for variable gain amp
|
except KeyError: pass #nf0 is not needed for variable gain amp
|
||||||
@@ -84,19 +188,28 @@ class Amp(AmpBase):
|
|||||||
try:
|
try:
|
||||||
nf_coef = kwargs.pop('nf_coef')
|
nf_coef = kwargs.pop('nf_coef')
|
||||||
except KeyError: #nf_coef is expected for openroadm amp
|
except KeyError: #nf_coef is expected for openroadm amp
|
||||||
print(f'missing nf_coef input for amplifier: {type_variety} in eqpt_config.json')
|
raise EquipmentConfigError(f'missing nf_coef input for amplifier: {type_variety} in equipment config')
|
||||||
exit()
|
|
||||||
nf_def = Model_openroadm(nf_coef)
|
nf_def = Model_openroadm(nf_coef)
|
||||||
return cls(**{**kwargs, **json_data, 'nf_model': nf_def})
|
elif type_def == 'dual_stage':
|
||||||
|
try: #nf_ram and gain_ram are expected for a hybrid amp
|
||||||
|
preamp_variety = kwargs.pop('preamp_variety')
|
||||||
|
booster_variety = kwargs.pop('booster_variety')
|
||||||
|
except KeyError:
|
||||||
|
raise EquipmentConfigError(f'missing preamp/booster variety input for amplifier: {type_variety} in equipment config')
|
||||||
|
dual_stage_def = Model_dual_stage(preamp_variety, booster_variety)
|
||||||
|
|
||||||
|
with open(config, encoding='utf-8') as f:
|
||||||
|
json_data = load(f)
|
||||||
|
|
||||||
|
return cls(**{**kwargs, **json_data,
|
||||||
|
'nf_model': nf_def, 'dual_stage_model': dual_stage_def})
|
||||||
|
|
||||||
|
|
||||||
def nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
def nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
||||||
if nf_min < -10:
|
if nf_min < -10:
|
||||||
print(f'Invalid nf_min value {nf_min!r} for amplifier {type_variety}')
|
raise EquipmentConfigError(f'Invalid nf_min value {nf_min!r} for amplifier {type_variety}')
|
||||||
exit()
|
|
||||||
if nf_max < -10:
|
if nf_max < -10:
|
||||||
print(f'Invalid nf_max value {nf_max!r} for amplifier {type_variety}')
|
raise EquipmentConfigError(f'Invalid nf_max value {nf_max!r} for amplifier {type_variety}')
|
||||||
exit()
|
|
||||||
|
|
||||||
# NF estimation model based on nf_min and nf_max
|
# NF estimation model based on nf_min and nf_max
|
||||||
# delta_p: max power dB difference between first and second stage coils
|
# delta_p: max power dB difference between first and second stage coils
|
||||||
@@ -111,8 +224,7 @@ def nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
|||||||
nf1 = lin2db(db2lin(nf_min) - db2lin(nf2)/db2lin(g1a_max))
|
nf1 = lin2db(db2lin(nf_min) - db2lin(nf2)/db2lin(g1a_max))
|
||||||
|
|
||||||
if nf1 < 4:
|
if nf1 < 4:
|
||||||
print(f'First coil value too low {nf1} for amplifier {type_variety}')
|
raise EquipmentConfigError(f'First coil value too low {nf1} for amplifier {type_variety}')
|
||||||
exit()
|
|
||||||
|
|
||||||
# Check 1 dB < delta_p < 6 dB to ensure nf_min and nf_max values make sense.
|
# Check 1 dB < delta_p < 6 dB to ensure nf_min and nf_max values make sense.
|
||||||
# There shouldn't be high nf differences between the two coils:
|
# There shouldn't be high nf differences between the two coils:
|
||||||
@@ -123,21 +235,18 @@ def nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
|||||||
g1a_max = lin2db(db2lin(nf2) / (db2lin(nf_min) - db2lin(nf1)))
|
g1a_max = lin2db(db2lin(nf2) / (db2lin(nf_min) - db2lin(nf1)))
|
||||||
delta_p = gain_max - g1a_max
|
delta_p = gain_max - g1a_max
|
||||||
g1a_min = gain_min - (gain_max-gain_min) - delta_p
|
g1a_min = gain_min - (gain_max-gain_min) - delta_p
|
||||||
if not 1 < delta_p < 6:
|
if not 1 < delta_p < 11:
|
||||||
print(f'Computed \N{greek capital letter delta}P invalid \
|
raise EquipmentConfigError(f'Computed \N{greek capital letter delta}P invalid \
|
||||||
\n 1st coil vs 2nd coil calculated DeltaP {delta_p:.2f} for \
|
\n 1st coil vs 2nd coil calculated DeltaP {delta_p:.2f} for \
|
||||||
\n amplifier {type_variety} is not valid: revise inputs \
|
\n amplifier {type_variety} is not valid: revise inputs \
|
||||||
\n calculated 1st coil NF = {nf1:.2f}, 2nd coil NF = {nf2:.2f}')
|
\n calculated 1st coil NF = {nf1:.2f}, 2nd coil NF = {nf2:.2f}')
|
||||||
exit()
|
|
||||||
# Check calculated values for nf1 and nf2
|
# Check calculated values for nf1 and nf2
|
||||||
calc_nf_min = lin2db(db2lin(nf1) + db2lin(nf2)/db2lin(g1a_max))
|
calc_nf_min = lin2db(db2lin(nf1) + db2lin(nf2)/db2lin(g1a_max))
|
||||||
if not isclose(nf_min, calc_nf_min, abs_tol=0.01):
|
if not isclose(nf_min, calc_nf_min, abs_tol=0.01):
|
||||||
print(f'nf_min does not match calc_nf_min, {nf_min} vs {calc_nf_min} for amp {type_variety}')
|
raise EquipmentConfigError(f'nf_min does not match calc_nf_min, {nf_min} vs {calc_nf_min} for amp {type_variety}')
|
||||||
exit()
|
|
||||||
calc_nf_max = lin2db(db2lin(nf1) + db2lin(nf2)/db2lin(g1a_min))
|
calc_nf_max = lin2db(db2lin(nf1) + db2lin(nf2)/db2lin(g1a_min))
|
||||||
if not isclose(nf_max, calc_nf_max, abs_tol=0.01):
|
if not isclose(nf_max, calc_nf_max, abs_tol=0.01):
|
||||||
print(f'nf_max does not match calc_nf_max, {nf_max} vs {calc_nf_max} for amp {type_variety}')
|
raise EquipmentConfigError(f'nf_max does not match calc_nf_max, {nf_max} vs {calc_nf_max} for amp {type_variety}')
|
||||||
exit()
|
|
||||||
|
|
||||||
return nf1, nf2, delta_p
|
return nf1, nf2, delta_p
|
||||||
|
|
||||||
@@ -145,7 +254,7 @@ def edfa_nf(gain_target, variety_type, equipment):
|
|||||||
amp_params = equipment['Edfa'][variety_type]
|
amp_params = equipment['Edfa'][variety_type]
|
||||||
amp = Edfa(
|
amp = Edfa(
|
||||||
uid = f'calc_NF',
|
uid = f'calc_NF',
|
||||||
params = amp_params._asdict(),
|
params = amp_params.__dict__,
|
||||||
operational = {
|
operational = {
|
||||||
'gain_target': gain_target,
|
'gain_target': gain_target,
|
||||||
'tilt_target': 0
|
'tilt_target': 0
|
||||||
@@ -172,10 +281,8 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F
|
|||||||
trx_params = {**mode_params}
|
trx_params = {**mode_params}
|
||||||
# sanity check: spacing baudrate must be smaller than min spacing
|
# sanity check: spacing baudrate must be smaller than min spacing
|
||||||
if trx_params['baud_rate'] > trx_params['min_spacing'] :
|
if trx_params['baud_rate'] > trx_params['min_spacing'] :
|
||||||
msg = f'Inconsistency in equipment library:\n Transpoder "{trx_type_variety}" mode "{trx_params["format"]}" '+\
|
raise EquipmentConfigError(f'Inconsistency in equipment library:\n Transpoder "{trx_type_variety}" mode "{trx_params["format"]}" '+\
|
||||||
f'has baud rate: {trx_params["baud_rate"]*1e-9} GHz greater than min_spacing {trx_params["min_spacing"]*1e-9}.'
|
f'has baud rate: {trx_params["baud_rate"]*1e-9} GHz greater than min_spacing {trx_params["min_spacing"]*1e-9}.')
|
||||||
print(msg)
|
|
||||||
exit()
|
|
||||||
else:
|
else:
|
||||||
mode_params = {"format": "undetermined",
|
mode_params = {"format": "undetermined",
|
||||||
"baud_rate": None,
|
"baud_rate": None,
|
||||||
@@ -195,9 +302,7 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F
|
|||||||
# print(f'spacing {temp}')
|
# print(f'spacing {temp}')
|
||||||
except StopIteration :
|
except StopIteration :
|
||||||
if error_message:
|
if error_message:
|
||||||
print(f'could not find tsp : {trx_type_variety} with mode: {trx_mode} in eqpt library')
|
raise EquipmentConfigError(f'Computation stoped: could not find tsp : {trx_type_variety} with mode: {trx_mode} in eqpt library')
|
||||||
print('Computation stopped.')
|
|
||||||
exit()
|
|
||||||
else:
|
else:
|
||||||
# default transponder charcteristics
|
# default transponder charcteristics
|
||||||
# mainly used with transmission_main_example.py
|
# mainly used with transmission_main_example.py
|
||||||
@@ -222,8 +327,8 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F
|
|||||||
def automatic_spacing(baud_rate):
|
def automatic_spacing(baud_rate):
|
||||||
"""return the min possible channel spacing for a given baud rate"""
|
"""return the min possible channel spacing for a given baud rate"""
|
||||||
# TODO : this should parametrized in a cfg file
|
# TODO : this should parametrized in a cfg file
|
||||||
spacing_list = [(33e9,37.5e9), (38e9,50e9), (50e9,62.5e9), (67e9,75e9), (92e9,100e9)] #list of possible tuples
|
# list of possible tuples [(max_baud_rate, spacing_for_this_baud_rate)]
|
||||||
#[(max_baud_rate, spacing_for_this_baud_rate)]
|
spacing_list = [(33e9, 37.5e9), (38e9, 50e9), (50e9, 62.5e9), (67e9, 75e9), (92e9, 100e9)]
|
||||||
return min((s[1] for s in spacing_list if s[0] > baud_rate), default=baud_rate*1.2)
|
return min((s[1] for s in spacing_list if s[0] > baud_rate), default=baud_rate*1.2)
|
||||||
|
|
||||||
def automatic_nch(f_min, f_max, spacing):
|
def automatic_nch(f_min, f_max, spacing):
|
||||||
@@ -243,6 +348,34 @@ def update_trx_osnr(equipment):
|
|||||||
m['OSNR'] = m['OSNR'] + equipment['SI']['default'].sys_margins
|
m['OSNR'] = m['OSNR'] + equipment['SI']['default'].sys_margins
|
||||||
return equipment
|
return equipment
|
||||||
|
|
||||||
|
def update_dual_stage(equipment):
|
||||||
|
edfa_dict = equipment['Edfa']
|
||||||
|
for edfa in edfa_dict.values():
|
||||||
|
if edfa.type_def == 'dual_stage':
|
||||||
|
edfa_preamp = edfa_dict[edfa.dual_stage_model.preamp_variety]
|
||||||
|
edfa_booster = edfa_dict[edfa.dual_stage_model.booster_variety]
|
||||||
|
for key, value in edfa_preamp.__dict__.items():
|
||||||
|
attr_k = 'preamp_' + key
|
||||||
|
setattr(edfa, attr_k, value)
|
||||||
|
for key, value in edfa_booster.__dict__.items():
|
||||||
|
attr_k = 'booster_' + key
|
||||||
|
setattr(edfa, attr_k, value)
|
||||||
|
edfa.p_max = edfa_booster.p_max
|
||||||
|
edfa.gain_flatmax = edfa_booster.gain_flatmax + edfa_preamp.gain_flatmax
|
||||||
|
if edfa.gain_min < edfa_preamp.gain_min:
|
||||||
|
raise EquipmentConfigError(f'Dual stage {edfa.type_variety} min gain is lower than its preamp min gain')
|
||||||
|
return equipment
|
||||||
|
|
||||||
|
def roadm_restrictions_sanity_check(equipment):
|
||||||
|
""" verifies that booster and preamp restrictions specified in roadm equipment are listed
|
||||||
|
in the edfa.
|
||||||
|
"""
|
||||||
|
restrictions = equipment['Roadm']['default'].restrictions['booster_variety_list'] + \
|
||||||
|
equipment['Roadm']['default'].restrictions['preamp_variety_list']
|
||||||
|
for amp_name in restrictions:
|
||||||
|
if amp_name not in equipment['Edfa']:
|
||||||
|
raise EquipmentConfigError(f'ROADM restriction {amp_name} does not refer to a defined EDFA name')
|
||||||
|
|
||||||
def equipment_from_json(json_data, filename):
|
def equipment_from_json(json_data, filename):
|
||||||
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
||||||
edfa type type_variety, fiber type_variety
|
edfa type type_variety, fiber type_variety
|
||||||
@@ -259,13 +392,10 @@ def equipment_from_json(json_data, filename):
|
|||||||
for entry in entries:
|
for entry in entries:
|
||||||
subkey = entry.get('type_variety', 'default')
|
subkey = entry.get('type_variety', 'default')
|
||||||
if key == 'Edfa':
|
if key == 'Edfa':
|
||||||
if 'advanced_config_from_json' in entry:
|
equipment[key][subkey] = Amp.from_json(filename, **entry)
|
||||||
config = Path(filename).parent / entry.pop('advanced_config_from_json')
|
|
||||||
equipment[key][subkey] = Amp.from_advanced_json(config, **entry)
|
|
||||||
else:
|
|
||||||
config = Path(filename).parent / 'default_edfa_config.json'
|
|
||||||
equipment[key][subkey] = Amp.from_default_json(config, **entry)
|
|
||||||
else:
|
else:
|
||||||
equipment[key][subkey] = typ(**entry)
|
equipment[key][subkey] = typ(**entry)
|
||||||
equipment = update_trx_osnr(equipment)
|
equipment = update_trx_osnr(equipment)
|
||||||
|
equipment = update_dual_stage(equipment)
|
||||||
|
roadm_restrictions_sanity_check(equipment)
|
||||||
return equipment
|
return equipment
|
||||||
|
|||||||
29
gnpy/core/exceptions.py
Normal file
29
gnpy/core/exceptions.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
gnpy.core.exceptions
|
||||||
|
====================
|
||||||
|
|
||||||
|
Exceptions thrown by other gnpy modules
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurationError(Exception):
|
||||||
|
'''User-provided configuration contains an error'''
|
||||||
|
|
||||||
|
class EquipmentConfigError(ConfigurationError):
|
||||||
|
'''Incomplete or wrong configuration within the equipment library'''
|
||||||
|
|
||||||
|
class NetworkTopologyError(ConfigurationError):
|
||||||
|
'''Topology of user-provided network is wrong'''
|
||||||
|
|
||||||
|
class ServiceError(Exception):
|
||||||
|
'''Service of user-provided request is wrong'''
|
||||||
|
|
||||||
|
class DisjunctionError(ServiceError):
|
||||||
|
'''Disjunction of user-provided request can not be satisfied'''
|
||||||
|
|
||||||
|
class SpectrumError(Exception):
|
||||||
|
'''Spectrum errors of the program'''
|
||||||
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
gnpy.core.info
|
gnpy.core.info
|
||||||
==============
|
==============
|
||||||
|
|
||||||
This module contains classes for modelling SpectralInformation.
|
This module contains classes for modelling :class:`SpectralInformation`.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
@@ -16,53 +16,34 @@ from json import loads
|
|||||||
from gnpy.core.utils import load_json
|
from gnpy.core.utils import load_json
|
||||||
from gnpy.core.equipment import automatic_nch, automatic_spacing
|
from gnpy.core.equipment import automatic_nch, automatic_spacing
|
||||||
|
|
||||||
class ConvenienceAccess:
|
class Power(namedtuple('Power', 'signal nli ase')):
|
||||||
|
"""carriers power in W"""
|
||||||
def __init_subclass__(cls):
|
|
||||||
for abbrev, field in getattr(cls, '_ABBREVS', {}).items():
|
|
||||||
setattr(cls, abbrev, property(lambda self, f=field: getattr(self, f)))
|
|
||||||
|
|
||||||
def update(self, **kwargs):
|
|
||||||
for abbrev, field in getattr(self, '_ABBREVS', {}).items():
|
|
||||||
if abbrev in kwargs:
|
|
||||||
kwargs[field] = kwargs.pop(abbrev)
|
|
||||||
return self._replace(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class Power(namedtuple('Power', 'signal nonlinear_interference amplified_spontaneous_emission'), ConvenienceAccess):
|
class Channel(namedtuple('Channel', 'channel_number frequency baud_rate roll_off power')):
|
||||||
|
pass
|
||||||
_ABBREVS = {'nli': 'nonlinear_interference',
|
|
||||||
'ase': 'amplified_spontaneous_emission',}
|
|
||||||
|
|
||||||
|
|
||||||
class Channel(namedtuple('Channel', 'channel_number frequency baud_rate roll_off power'), ConvenienceAccess):
|
class Pref(namedtuple('Pref', 'p_span0, p_spani, neq_ch ')):
|
||||||
|
"""noiseless reference power in dBm:
|
||||||
|
p_span0: inital target carrier power
|
||||||
|
p_spani: carrier power after element i
|
||||||
|
neq_ch: equivalent channel count in dB"""
|
||||||
|
|
||||||
_ABBREVS = {'channel': 'channel_number',
|
|
||||||
'num_chan': 'channel_number',
|
|
||||||
'ffs': 'frequency',
|
|
||||||
'freq': 'frequency',}
|
|
||||||
|
|
||||||
class Pref(namedtuple('Pref', 'p_span0, p_spani'), ConvenienceAccess):
|
class SpectralInformation(namedtuple('SpectralInformation', 'pref carriers')):
|
||||||
|
|
||||||
_ABBREVS = {'p0' : 'p_span0',
|
def __new__(cls, pref, carriers):
|
||||||
'pi' : 'p_spani'}
|
|
||||||
|
|
||||||
class SpectralInformation(namedtuple('SpectralInformation', 'pref carriers'), ConvenienceAccess):
|
|
||||||
|
|
||||||
def __new__(cls, pref=Pref(0, 0), *carriers):
|
|
||||||
return super().__new__(cls, pref, carriers)
|
return super().__new__(cls, pref, carriers)
|
||||||
|
|
||||||
def merge_input_spectral_information(*si):
|
|
||||||
"""mix channel combs of different baud rates and power"""
|
|
||||||
#TODO
|
|
||||||
pass
|
|
||||||
|
|
||||||
def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing):
|
def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing):
|
||||||
# pref in dB : convert power lin into power in dB
|
# pref in dB : convert power lin into power in dB
|
||||||
pref = lin2db(power * 1e3)
|
pref = lin2db(power * 1e3)
|
||||||
si = SpectralInformation(pref=Pref(pref, pref))
|
|
||||||
nb_channel = automatic_nch(f_min, f_max, spacing)
|
nb_channel = automatic_nch(f_min, f_max, spacing)
|
||||||
si = si.update(carriers=[
|
si = SpectralInformation(
|
||||||
|
pref=Pref(pref, pref, lin2db(nb_channel)),
|
||||||
|
carriers=[
|
||||||
Channel(f, (f_min+spacing*f),
|
Channel(f, (f_min+spacing*f),
|
||||||
baud_rate, roll_off, Power(power, 0, 0)) for f in range(1,nb_channel+1)
|
baud_rate, roll_off, Power(power, 0, 0)) for f in range(1,nb_channel+1)
|
||||||
])
|
])
|
||||||
@@ -81,11 +62,11 @@ if __name__ == '__main__':
|
|||||||
si = SpectralInformation()
|
si = SpectralInformation()
|
||||||
spacing = 0.05 # THz
|
spacing = 0.05 # THz
|
||||||
|
|
||||||
si = si.update(carriers=tuple(Channel(f+1, 191.3+spacing*(f+1), 32e9, 0.15, Power(1e-3, f, 1)) for f in range(96)))
|
si = si._replace(carriers=tuple(Channel(f+1, 191.3+spacing*(f+1), 32e9, 0.15, Power(1e-3, f, 1)) for f in range(96)))
|
||||||
|
|
||||||
print(f'si = {si}')
|
print(f'si = {si}')
|
||||||
print(f'si = {si.carriers[0].power.nli}')
|
print(f'si = {si.carriers[0].power.nli}')
|
||||||
print(f'si = {si.carriers[20].power.nli}')
|
print(f'si = {si.carriers[20].power.nli}')
|
||||||
si2 = si.update(carriers=tuple(c.update(power = c.power.update(nli = c.power.nli * 1e5))
|
si2 = si._replace(carriers=tuple(c._replace(power = c.power._replace(nli = c.power.nli * 1e5))
|
||||||
for c in si.carriers))
|
for c in si.carriers))
|
||||||
print(f'si2 = {si2}')
|
print(f'si2 = {si2}')
|
||||||
|
|||||||
@@ -11,15 +11,18 @@ This module contains functions for constructing networks of network elements.
|
|||||||
from gnpy.core.convert import convert_file
|
from gnpy.core.convert import convert_file
|
||||||
from networkx import DiGraph
|
from networkx import DiGraph
|
||||||
from numpy import arange
|
from numpy import arange
|
||||||
|
from scipy.interpolate import interp1d
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from os import path
|
from os import path
|
||||||
from operator import itemgetter
|
from operator import itemgetter, attrgetter
|
||||||
from gnpy.core import elements
|
from gnpy.core import elements
|
||||||
from gnpy.core.elements import Fiber, Edfa, Transceiver, Roadm, Fused
|
from gnpy.core.elements import Fiber, Edfa, Transceiver, Roadm, Fused, RamanFiber
|
||||||
from gnpy.core.equipment import edfa_nf
|
from gnpy.core.equipment import edfa_nf
|
||||||
|
from gnpy.core.exceptions import ConfigurationError, NetworkTopologyError
|
||||||
from gnpy.core.units import UNITS
|
from gnpy.core.units import UNITS
|
||||||
from gnpy.core.utils import load_json, save_json, round2float, db2lin, lin2db
|
from gnpy.core.utils import (load_json, save_json, round2float, db2lin,
|
||||||
from sys import exit
|
merge_amplifier_restrictions)
|
||||||
|
from gnpy.core.science_utils import SimParams
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
@@ -51,11 +54,12 @@ def network_from_json(json_data, equipment):
|
|||||||
variety = el_config.pop('type_variety', 'default')
|
variety = el_config.pop('type_variety', 'default')
|
||||||
if typ in equipment and variety in equipment[typ]:
|
if typ in equipment and variety in equipment[typ]:
|
||||||
extra_params = equipment[typ][variety]
|
extra_params = equipment[typ][variety]
|
||||||
el_config.setdefault('params', {}).update(extra_params._asdict())
|
temp = el_config.setdefault('params', {})
|
||||||
|
temp = merge_amplifier_restrictions(temp, extra_params.__dict__)
|
||||||
|
el_config['params'] = temp
|
||||||
elif typ in ['Edfa', 'Fiber']: # catch it now because the code will crash later!
|
elif typ in ['Edfa', 'Fiber']: # catch it now because the code will crash later!
|
||||||
print( f'The {typ} of variety type {variety} was not recognized:'
|
raise ConfigurationError(f'The {typ} of variety type {variety} was not recognized:'
|
||||||
'\nplease check it is properly defined in the eqpt_config json file')
|
'\nplease check it is properly defined in the eqpt_config json file')
|
||||||
exit()
|
|
||||||
cls = getattr(elements, typ)
|
cls = getattr(elements, typ)
|
||||||
el = cls(**el_config)
|
el = cls(**el_config)
|
||||||
g.add_node(el)
|
g.add_node(el)
|
||||||
@@ -65,11 +69,13 @@ def network_from_json(json_data, equipment):
|
|||||||
for cx in json_data['connections']:
|
for cx in json_data['connections']:
|
||||||
from_node, to_node = cx['from_node'], cx['to_node']
|
from_node, to_node = cx['from_node'], cx['to_node']
|
||||||
try:
|
try:
|
||||||
g.add_edge(nodes[from_node], nodes[to_node])
|
if isinstance(nodes[from_node], Fiber):
|
||||||
|
edge_length = nodes[from_node].params.length
|
||||||
|
else:
|
||||||
|
edge_length = 0.01
|
||||||
|
g.add_edge(nodes[from_node], nodes[to_node], weight = edge_length)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
msg = f'In {__name__} network_from_json function:\n\tcan not find {from_node} or {to_node} defined in {cx}'
|
raise NetworkTopologyError(f'can not find {from_node} or {to_node} defined in {cx}')
|
||||||
print(msg)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
return g
|
return g
|
||||||
|
|
||||||
@@ -86,16 +92,27 @@ def network_to_json(network):
|
|||||||
data.update(connections)
|
data.update(connections)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def select_edfa(gain_target, power_target, equipment):
|
def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restrictions=None):
|
||||||
"""amplifer selection algorithm
|
"""amplifer selection algorithm
|
||||||
@Orange Jean-Luc Augé
|
@Orange Jean-Luc Augé
|
||||||
"""
|
"""
|
||||||
Edfa_list = namedtuple('Edfa_list', 'variety power gain nf')
|
Edfa_list = namedtuple('Edfa_list', 'variety power gain_min nf')
|
||||||
TARGET_EXTENDED_GAIN = 2.1
|
TARGET_EXTENDED_GAIN = equipment['Span']['default'].target_extended_gain
|
||||||
#MAX_EXTENDED_GAIN = 5
|
|
||||||
edfa_dict = equipment['Edfa']
|
# for roadm restriction only: create a dict including not allowed for design amps
|
||||||
|
# because main use case is to have specific radm amp which are not allowed for ILA
|
||||||
|
# with the auto design
|
||||||
|
edfa_dict = {name: amp for (name, amp) in equipment['Edfa'].items()
|
||||||
|
if restrictions is None or name in restrictions}
|
||||||
|
|
||||||
pin = power_target - gain_target
|
pin = power_target - gain_target
|
||||||
|
|
||||||
|
# create 2 list of available amplifiers with relevant attributes for their selection
|
||||||
|
|
||||||
|
# edfa list with:
|
||||||
|
# extended gain min allowance of 3dB: could be parametrized, but a bit complex
|
||||||
|
# extended gain max allowance TARGET_EXTENDED_GAIN is coming from eqpt_config.json
|
||||||
|
# power attribut include power AND gain limitations
|
||||||
edfa_list = [Edfa_list(
|
edfa_list = [Edfa_list(
|
||||||
variety=edfa_variety,
|
variety=edfa_variety,
|
||||||
power=min(
|
power=min(
|
||||||
@@ -105,88 +122,118 @@ def select_edfa(gain_target, power_target, equipment):
|
|||||||
edfa.p_max
|
edfa.p_max
|
||||||
)
|
)
|
||||||
-power_target,
|
-power_target,
|
||||||
gain=edfa.gain_flatmax-gain_target,
|
gain_min=
|
||||||
|
gain_target+3
|
||||||
|
-edfa.gain_min,
|
||||||
nf=edfa_nf(gain_target, edfa_variety, equipment)) \
|
nf=edfa_nf(gain_target, edfa_variety, equipment)) \
|
||||||
for edfa_variety, edfa in edfa_dict.items()
|
for edfa_variety, edfa in edfa_dict.items()
|
||||||
if edfa.allowed_for_design]
|
if ((edfa.allowed_for_design or restrictions is not None) and not edfa.raman)]
|
||||||
|
|
||||||
acceptable_gain_list = \
|
#consider a Raman list because of different gain_min requirement:
|
||||||
list(filter(lambda x : x.gain>-TARGET_EXTENDED_GAIN, edfa_list))
|
#do not allow extended gain min for Raman
|
||||||
if len(acceptable_gain_list) < 1:
|
raman_list = [Edfa_list(
|
||||||
#no amplifier satisfies the required gain, so pick the highest gain:
|
variety=edfa_variety,
|
||||||
gain_max = max(edfa_list, key=itemgetter(2)).gain
|
power=min(
|
||||||
#pick up all amplifiers that share this max gain:
|
pin
|
||||||
acceptable_gain_list = \
|
+edfa.gain_flatmax
|
||||||
list(filter(lambda x : x.gain-gain_max>-0.1, edfa_list))
|
+TARGET_EXTENDED_GAIN,
|
||||||
acceptable_power_list = \
|
edfa.p_max
|
||||||
list(filter(lambda x : x.power>=0, acceptable_gain_list))
|
)
|
||||||
|
-power_target,
|
||||||
|
gain_min=
|
||||||
|
gain_target
|
||||||
|
-edfa.gain_min,
|
||||||
|
nf=edfa_nf(gain_target, edfa_variety, equipment))
|
||||||
|
for edfa_variety, edfa in edfa_dict.items()
|
||||||
|
if (edfa.allowed_for_design and edfa.raman)] \
|
||||||
|
if raman_allowed else []
|
||||||
|
|
||||||
|
#merge raman and edfa lists
|
||||||
|
amp_list = edfa_list + raman_list
|
||||||
|
|
||||||
|
#filter on min gain limitation:
|
||||||
|
acceptable_gain_min_list = [x for x in amp_list if x.gain_min>0]
|
||||||
|
|
||||||
|
if len(acceptable_gain_min_list) < 1:
|
||||||
|
#do not take this empty list into account for the rest of the code
|
||||||
|
#but issue a warning to the user and do not consider Raman
|
||||||
|
#Raman below min gain should not be allowed because i is meant to be a design requirement
|
||||||
|
#and raman padding at the amplifier input is impossible!
|
||||||
|
|
||||||
|
if len(edfa_list) < 1:
|
||||||
|
raise ConfigurationError(f'auto_design could not find any amplifier \
|
||||||
|
to satisfy min gain requirement in node {uid} \
|
||||||
|
please increase span fiber padding')
|
||||||
|
else:
|
||||||
|
# TODO: convert to logging
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'WARNING: target gain in node {uid} is below all available amplifiers min gain: \
|
||||||
|
amplifier input padding will be assumed, consider increase span fiber padding instead'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
acceptable_gain_min_list = edfa_list
|
||||||
|
|
||||||
|
#filter on gain+power limitation:
|
||||||
|
#this list checks both the gain and the power requirement
|
||||||
|
#because of the way .power is calculated in the list
|
||||||
|
acceptable_power_list = [x for x in acceptable_gain_min_list if x.power>0]
|
||||||
if len(acceptable_power_list) < 1:
|
if len(acceptable_power_list) < 1:
|
||||||
#no amplifier satisfies the required power, so pick the highest power:
|
#no amplifier satisfies the required power, so pick the highest power(s):
|
||||||
power_max = \
|
power_max = max(acceptable_gain_min_list, key=attrgetter('power')).power
|
||||||
max(acceptable_gain_list, key=itemgetter(1)).power
|
#check and pick if other amplifiers may have a similar gain/power
|
||||||
#pick up all amplifiers that share this max gain:
|
#allow a 0.3dB power range
|
||||||
acceptable_power_list = \
|
#this allows to chose an amplifier with a better NF subsequentely
|
||||||
list(filter(lambda x : x.power-power_max>-0.1, acceptable_gain_list))
|
acceptable_power_list = [x for x in acceptable_gain_min_list
|
||||||
|
if x.power-power_max>-0.3]
|
||||||
|
|
||||||
|
|
||||||
# gain and power requirements are resolved,
|
# gain and power requirements are resolved,
|
||||||
# =>chose the amp with the best NF among the acceptable ones:
|
# =>chose the amp with the best NF among the acceptable ones:
|
||||||
return min(acceptable_power_list, key=itemgetter(3)).variety #filter on NF
|
selected_edfa = min(acceptable_power_list, key=attrgetter('nf')) #filter on NF
|
||||||
|
#check what are the gain and power limitations of this amp
|
||||||
|
power_reduction = round(min(selected_edfa.power, 0),2)
|
||||||
|
if power_reduction < -0.5:
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'WARNING: target gain and power in node {uid}\n \
|
||||||
|
is beyond all available amplifiers capabilities and/or extended_gain_range:\n\
|
||||||
|
a power reduction of {power_reduction} is applied\n'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def set_roadm_loss(network, equipment, pref_ch_db):
|
return selected_edfa.variety, power_reduction
|
||||||
roadms = [roadm for roadm in network if isinstance(roadm, Roadm)]
|
|
||||||
power_mode = equipment['Spans']['default'].power_mode
|
|
||||||
default_roadm_loss = equipment['Roadms']['default'].gain_mode_default_loss
|
|
||||||
pout_target = equipment['Roadms']['default'].power_mode_pout_target
|
|
||||||
roadm_loss = pref_ch_db - pout_target
|
|
||||||
|
|
||||||
for roadm in roadms:
|
def target_power(network, node, equipment): #get_fiber_dp
|
||||||
if power_mode:
|
|
||||||
roadm.loss = roadm_loss
|
|
||||||
roadm.target_pch_out_db = pout_target
|
|
||||||
elif roadm.loss == None:
|
|
||||||
roadm.loss = default_roadm_loss
|
|
||||||
|
|
||||||
def target_power(dp_from_gain, network, node, equipment): #get_fiber_dp
|
|
||||||
SPAN_LOSS_REF = 20
|
SPAN_LOSS_REF = 20
|
||||||
POWER_SLOPE = 0.3
|
POWER_SLOPE = 0.3
|
||||||
power_mode = equipment['Spans']['default'].power_mode
|
power_mode = equipment['Span']['default'].power_mode
|
||||||
dp_range = list(equipment['Spans']['default'].delta_power_range_db)
|
dp_range = list(equipment['Span']['default'].delta_power_range_db)
|
||||||
node_loss = span_loss(network, node)
|
node_loss = span_loss(network, node)
|
||||||
|
|
||||||
dp_gain_mode = 0
|
|
||||||
try:
|
try:
|
||||||
dp_power_mode = round2float((node_loss - SPAN_LOSS_REF) * POWER_SLOPE, dp_range[2])
|
dp = round2float((node_loss - SPAN_LOSS_REF) * POWER_SLOPE, dp_range[2])
|
||||||
dp_power_mode = max(dp_range[0], dp_power_mode)
|
dp = max(dp_range[0], dp)
|
||||||
dp_power_mode = min(dp_range[1], dp_power_mode)
|
dp = min(dp_range[1], dp)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print(f'invalid delta_power_range_db definition in eqpt_config[Spans]'
|
raise ConfigurationError(f'invalid delta_power_range_db definition in eqpt_config[Span]'
|
||||||
f'delta_power_range_db: [lower_bound, upper_bound, step]')
|
f'delta_power_range_db: [lower_bound, upper_bound, step]')
|
||||||
exit()
|
|
||||||
|
|
||||||
if dp_from_gain:
|
|
||||||
dp_power_mode = dp_from_gain
|
|
||||||
dp_gain_mode = dp_from_gain
|
|
||||||
if isinstance(node, Roadm):
|
if isinstance(node, Roadm):
|
||||||
dp_power_mode = 0
|
dp = 0
|
||||||
|
|
||||||
dp = dp_power_mode if power_mode else dp_gain_mode
|
|
||||||
#print(f'{repr(node)} delta power in:\n{dp}dB')
|
|
||||||
|
|
||||||
return dp
|
return dp
|
||||||
|
|
||||||
|
|
||||||
def prev_node_generator(network, node):
|
def prev_node_generator(network, node):
|
||||||
"""fused spans interest:
|
"""fused spans interest:
|
||||||
iterate over all predecessors while they are Fused or Fiber type"""
|
iterate over all predecessors while they are Fused or Fiber type"""
|
||||||
try:
|
try:
|
||||||
prev_node = next(n for n in network.predecessors(node))
|
prev_node = next(n for n in network.predecessors(node))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
msg = f'In {__name__} prev_node_generator function:\n\t{node.uid} is not properly connected, please check network topology'
|
raise NetworkTopologyError(f'Node {node.uid} is not properly connected, please check network topology')
|
||||||
print(msg)
|
|
||||||
logger.critical(msg)
|
|
||||||
exit(1)
|
|
||||||
# yield and re-iterate
|
# 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 prev_node
|
||||||
yield from prev_node_generator(network, prev_node)
|
yield from prev_node_generator(network, prev_node)
|
||||||
else:
|
else:
|
||||||
@@ -198,10 +245,9 @@ def next_node_generator(network, node):
|
|||||||
try:
|
try:
|
||||||
next_node = next(n for n in network.successors(node))
|
next_node = next(n for n in network.successors(node))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
print(f'In {__name__} next_node_generator function:\n\t{node.uid} is not properly connected, please check network topology')
|
raise NetworkTopologyError('Node {node.uid} is not properly connected, please check network topology')
|
||||||
exit(1)
|
|
||||||
# yield and re-iterate
|
# 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 next_node
|
||||||
yield from next_node_generator(network, next_node)
|
yield from next_node_generator(network, next_node)
|
||||||
else:
|
else:
|
||||||
@@ -243,23 +289,22 @@ def find_last_node(network, node):
|
|||||||
pass
|
pass
|
||||||
return this_node
|
return this_node
|
||||||
|
|
||||||
def set_amplifier_voa(amp, pref_total_db, power_mode):
|
def set_amplifier_voa(amp, power_target, power_mode):
|
||||||
VOA_MARGIN = 0
|
VOA_MARGIN = 1 #do not maximize the VOA optimization
|
||||||
if amp.operational.out_voa is None:
|
if amp.out_voa is None:
|
||||||
if power_mode:
|
if power_mode:
|
||||||
gain_target = amp.operational.gain_target
|
gain_target = amp.effective_gain
|
||||||
pout = pref_total_db + amp.dp_db
|
voa = min(amp.params.p_max-power_target,
|
||||||
voa = min(amp.params.p_max-pout,
|
amp.params.gain_flatmax-amp.effective_gain)
|
||||||
amp.params.gain_flatmax-amp.operational.gain_target)
|
voa = max(round2float(max(voa, 0), 0.5) - VOA_MARGIN, 0) if amp.params.out_voa_auto else 0
|
||||||
voa = round2float(max(voa, 0), 0.5) - VOA_MARGIN if amp.params.out_voa_auto else 0
|
amp.delta_p = amp.delta_p + voa
|
||||||
amp.dp_db = amp.dp_db + voa
|
amp.effective_gain = amp.effective_gain + voa
|
||||||
amp.operational.gain_target = amp.operational.gain_target + voa
|
|
||||||
else:
|
else:
|
||||||
voa = 0 # no output voa optimization in gain mode
|
voa = 0 # no output voa optimization in gain mode
|
||||||
amp.operational.out_voa = voa
|
amp.out_voa = voa
|
||||||
|
|
||||||
def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
||||||
power_mode = equipment['Spans']['default'].power_mode
|
power_mode = equipment['Span']['default'].power_mode
|
||||||
next_oms = (n for n in network.successors(roadm) if not isinstance(n, Transceiver))
|
next_oms = (n for n in network.successors(roadm) if not isinstance(n, Transceiver))
|
||||||
for oms in next_oms:
|
for oms in next_oms:
|
||||||
#go through all the OMS departing from the Roadm
|
#go through all the OMS departing from the Roadm
|
||||||
@@ -270,30 +315,82 @@ def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
|||||||
# node = find_last_node(next_node)
|
# node = find_last_node(next_node)
|
||||||
# next_node = next(n for n in network.successors(node))
|
# next_node = next(n for n in network.successors(node))
|
||||||
# next_node = find_last_node(next_node)
|
# next_node = find_last_node(next_node)
|
||||||
prev_dp = 0
|
|
||||||
dp = 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
|
||||||
while True:
|
while True:
|
||||||
#go through all nodes in the OMS (loop until next Roadm instance)
|
#go through all nodes in the OMS (loop until next Roadm instance)
|
||||||
if isinstance(node, Edfa):
|
if isinstance(node, Edfa):
|
||||||
node_loss = span_loss(network, prev_node)
|
node_loss = span_loss(network, prev_node)
|
||||||
dp_from_gain = prev_dp + node.operational.gain_target - node_loss \
|
voa = node.out_voa if node.out_voa else 0
|
||||||
if node.operational.gain_target > 0 else None
|
if node.delta_p is None:
|
||||||
dp = target_power(dp_from_gain, network, next_node, equipment)
|
dp = target_power(network, next_node, equipment)
|
||||||
gain_target = node_loss + dp - prev_dp
|
else:
|
||||||
|
dp = node.delta_p
|
||||||
|
gain_from_dp = node_loss + dp - prev_dp + prev_voa
|
||||||
|
if node.effective_gain is None or power_mode:
|
||||||
|
gain_target = gain_from_dp
|
||||||
|
else: #gain mode with effective_gain
|
||||||
|
gain_target = node.effective_gain
|
||||||
|
dp = prev_dp - node_loss + gain_target
|
||||||
|
|
||||||
if power_mode:
|
power_target = pref_total_db + dp
|
||||||
node.dp_db = dp
|
|
||||||
node.operational.gain_target = gain_target
|
raman_allowed = False
|
||||||
|
if isinstance(prev_node, Fiber):
|
||||||
|
max_fiber_lineic_loss_for_raman = \
|
||||||
|
equipment['Span']['default'].max_fiber_lineic_loss_for_raman
|
||||||
|
raman_allowed = prev_node.params.loss_coef < max_fiber_lineic_loss_for_raman
|
||||||
|
|
||||||
|
# implementation of restrictions on roadm boosters
|
||||||
|
if isinstance(prev_node,Roadm):
|
||||||
|
if prev_node.restrictions['booster_variety_list']:
|
||||||
|
restrictions = prev_node.restrictions['booster_variety_list']
|
||||||
|
else:
|
||||||
|
restrictions = None
|
||||||
|
elif isinstance(next_node,Roadm):
|
||||||
|
# implementation of restrictions on roadm preamp
|
||||||
|
if next_node.restrictions['preamp_variety_list']:
|
||||||
|
restrictions = next_node.restrictions['preamp_variety_list']
|
||||||
|
else:
|
||||||
|
restrictions = None
|
||||||
|
else:
|
||||||
|
restrictions = None
|
||||||
|
|
||||||
if node.params.type_variety == '':
|
if node.params.type_variety == '':
|
||||||
power_target = pref_total_db + dp
|
edfa_variety, power_reduction = select_edfa(raman_allowed,
|
||||||
edfa_variety = select_edfa(gain_target, power_target, equipment)
|
gain_target, power_target, equipment, node.uid, restrictions)
|
||||||
extra_params = equipment['Edfa'][edfa_variety]
|
extra_params = equipment['Edfa'][edfa_variety]
|
||||||
node.params.update_params(extra_params._asdict())
|
node.params.update_params(extra_params.__dict__)
|
||||||
set_amplifier_voa(node, pref_total_db, power_mode)
|
dp += power_reduction
|
||||||
|
gain_target += power_reduction
|
||||||
|
elif node.params.raman and not raman_allowed:
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'WARNING: raman is used in node {node.uid}\n \
|
||||||
|
but fiber lineic loss is above threshold\n'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
|
||||||
|
node.delta_p = dp if power_mode else None
|
||||||
|
node.effective_gain = gain_target
|
||||||
|
set_amplifier_voa(node, power_target, power_mode)
|
||||||
if isinstance(next_node, Roadm) or isinstance(next_node, Transceiver):
|
if isinstance(next_node, Roadm) or isinstance(next_node, Transceiver):
|
||||||
break
|
break
|
||||||
prev_dp = dp
|
prev_dp = dp
|
||||||
|
prev_voa = voa
|
||||||
prev_node = node
|
prev_node = node
|
||||||
node = next_node
|
node = next_node
|
||||||
# print(f'{node.uid}')
|
# print(f'{node.uid}')
|
||||||
@@ -309,13 +406,25 @@ def add_egress_amplifier(network, node):
|
|||||||
amp = Edfa(
|
amp = Edfa(
|
||||||
uid = f'Edfa{i}_{node.uid}',
|
uid = f'Edfa{i}_{node.uid}',
|
||||||
params = {},
|
params = {},
|
||||||
|
metadata = {
|
||||||
|
'location': {
|
||||||
|
'latitude': (node.lat * 2 + next_node.lat * 2) / 4,
|
||||||
|
'longitude': (node.lng * 2 + next_node.lng * 2) / 4,
|
||||||
|
'city': node.loc.city,
|
||||||
|
'region': node.loc.region,
|
||||||
|
}
|
||||||
|
},
|
||||||
operational = {
|
operational = {
|
||||||
'gain_target': 0,
|
'gain_target': None,
|
||||||
'tilt_target': 0,
|
'tilt_target': 0,
|
||||||
})
|
})
|
||||||
network.add_node(amp)
|
network.add_node(amp)
|
||||||
network.add_edge(node, amp)
|
if isinstance(node,Fiber):
|
||||||
network.add_edge(amp, next_node)
|
edgeweight = node.params.length
|
||||||
|
else:
|
||||||
|
edgeweight = 0.01
|
||||||
|
network.add_edge(node, amp, weight = edgeweight)
|
||||||
|
network.add_edge(amp, next_node, weight = 0.01)
|
||||||
|
|
||||||
|
|
||||||
def calculate_new_length(fiber_length, bounds, target_length):
|
def calculate_new_length(fiber_length, bounds, target_length):
|
||||||
@@ -351,9 +460,7 @@ def split_fiber(network, fiber, bounds, target_length, equipment):
|
|||||||
next_node = next(network.successors(fiber))
|
next_node = next(network.successors(fiber))
|
||||||
prev_node = next(network.predecessors(fiber))
|
prev_node = next(network.predecessors(fiber))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
|
raise NetworkTopologyError(f'Fiber {fiber.uid} is not properly connected, please check network topology')
|
||||||
print(f'In {__name__} split_fiber function:\n\t{fiber.uid} is not properly connected, please check network topology')
|
|
||||||
exit()
|
|
||||||
|
|
||||||
network.remove_node(fiber)
|
network.remove_node(fiber)
|
||||||
|
|
||||||
@@ -362,21 +469,39 @@ def split_fiber(network, fiber, bounds, target_length, equipment):
|
|||||||
fiber_params['con_in'] = fiber.con_in
|
fiber_params['con_in'] = fiber.con_in
|
||||||
fiber_params['con_out'] = fiber.con_out
|
fiber_params['con_out'] = fiber.con_out
|
||||||
|
|
||||||
for span in range(n_spans):
|
f = interp1d([prev_node.lng, next_node.lng], [prev_node.lat, next_node.lat])
|
||||||
|
xpos = [prev_node.lng + (next_node.lng - prev_node.lng) * (n+1)/(n_spans+1) for n in range(n_spans)]
|
||||||
|
ypos = f(xpos)
|
||||||
|
for span, lng, lat in zip(range(n_spans), xpos, ypos):
|
||||||
new_span = Fiber(uid = f'{fiber.uid}_({span+1}/{n_spans})',
|
new_span = Fiber(uid = f'{fiber.uid}_({span+1}/{n_spans})',
|
||||||
metadata = fiber.metadata,
|
metadata = {
|
||||||
|
'location': {
|
||||||
|
'latitude': lat,
|
||||||
|
'longitude': lng,
|
||||||
|
'city': fiber.loc.city,
|
||||||
|
'region': fiber.loc.region,
|
||||||
|
}
|
||||||
|
},
|
||||||
params = fiber_params)
|
params = fiber_params)
|
||||||
network.add_edge(prev_node, new_span)
|
if isinstance(prev_node,Fiber):
|
||||||
prev_node = new_span
|
edgeweight = prev_node.params.length
|
||||||
network.add_edge(prev_node, next_node)
|
|
||||||
|
|
||||||
def add_connector_loss(fibers, con_in, con_out, EOL):
|
|
||||||
for fiber in fibers:
|
|
||||||
if fiber.con_in is None: fiber.con_in = con_in
|
|
||||||
if fiber.con_out is None:
|
|
||||||
fiber.con_out = con_out #con_out includes EOL
|
|
||||||
else:
|
else:
|
||||||
fiber.con_out = fiber.con_out+EOL
|
edgeweight = 0.01
|
||||||
|
network.add_edge(prev_node, new_span, weight = edgeweight)
|
||||||
|
prev_node = new_span
|
||||||
|
if isinstance(prev_node,Fiber):
|
||||||
|
edgeweight = prev_node.params.length
|
||||||
|
else:
|
||||||
|
edgeweight = 0.01
|
||||||
|
network.add_edge(prev_node, next_node, weight = edgeweight)
|
||||||
|
|
||||||
|
def add_connector_loss(network, fibers, default_con_in, default_con_out, EOL):
|
||||||
|
for fiber in fibers:
|
||||||
|
if fiber.con_in is None: fiber.con_in = default_con_in
|
||||||
|
if fiber.con_out is None: fiber.con_out = default_con_out
|
||||||
|
next_node = next(n for n in network.successors(fiber))
|
||||||
|
if not isinstance(next_node, Fused):
|
||||||
|
fiber.con_out += EOL
|
||||||
|
|
||||||
def add_fiber_padding(network, fibers, padding):
|
def add_fiber_padding(network, fibers, padding):
|
||||||
"""last_fibers = (fiber for n in network.nodes()
|
"""last_fibers = (fiber for n in network.nodes()
|
||||||
@@ -388,33 +513,32 @@ def add_fiber_padding(network, fibers, padding):
|
|||||||
try:
|
try:
|
||||||
next_node = next(network.successors(fiber))
|
next_node = next(network.successors(fiber))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
msg = f'In {__name__} add_fiber_padding function:\n\t{fiber.uid} is not properly connected, please check network topology'
|
raise NetworkTopologyError(f'Fiber {fiber.uid} is not properly connected, please check network topology')
|
||||||
print(msg)
|
|
||||||
logger.critical(msg)
|
|
||||||
exit(1)
|
|
||||||
if this_span_loss < padding and not (isinstance(next_node, Fused)):
|
if this_span_loss < padding and not (isinstance(next_node, Fused)):
|
||||||
#add a padding att_in at the input of the 1st fiber:
|
#add a padding att_in at the input of the 1st fiber:
|
||||||
#address the case when several fibers are spliced together
|
#address the case when several fibers are spliced together
|
||||||
first_fiber = find_first_node(network, fiber)
|
first_fiber = find_first_node(network, fiber)
|
||||||
|
# in order to support no booster , fused might be placed
|
||||||
|
# just after a roadm: need to check that first_fiber is really a fiber
|
||||||
|
if isinstance(first_fiber,Fiber):
|
||||||
if first_fiber.att_in is None:
|
if first_fiber.att_in is None:
|
||||||
first_fiber.att_in = padding - this_span_loss
|
first_fiber.att_in = padding - this_span_loss
|
||||||
else:
|
else:
|
||||||
first_fiber.att_in = first_fiber.att_in + padding - this_span_loss
|
first_fiber.att_in = first_fiber.att_in + padding - this_span_loss
|
||||||
|
|
||||||
def build_network(network, equipment, pref_ch_db, pref_total_db):
|
def build_network(network, equipment, pref_ch_db, pref_total_db):
|
||||||
default_span_data = equipment['Spans']['default']
|
default_span_data = equipment['Span']['default']
|
||||||
max_length = int(default_span_data.max_length * UNITS[default_span_data.length_units])
|
max_length = int(default_span_data.max_length * UNITS[default_span_data.length_units])
|
||||||
min_length = max(int(default_span_data.padding/0.2*1e3),50_000)
|
min_length = max(int(default_span_data.padding/0.2*1e3),50_000)
|
||||||
bounds = range(min_length, max_length)
|
bounds = range(min_length, max_length)
|
||||||
target_length = max(min_length, 90_000)
|
target_length = max(min_length, 90_000)
|
||||||
con_in = default_span_data.con_in
|
default_con_in = default_span_data.con_in
|
||||||
con_out = default_span_data.con_out + default_span_data.EOL
|
default_con_out = default_span_data.con_out
|
||||||
padding = default_span_data.padding
|
padding = default_span_data.padding
|
||||||
|
|
||||||
#set raodm loss for gain_mode before to build network
|
#set roadm loss for gain_mode before to build network
|
||||||
set_roadm_loss(network, equipment, pref_ch_db)
|
|
||||||
fibers = [f for f in network.nodes() if isinstance(f, Fiber)]
|
fibers = [f for f in network.nodes() if isinstance(f, Fiber)]
|
||||||
add_connector_loss(fibers, con_in, con_out, default_span_data.EOL)
|
add_connector_loss(network, fibers, default_con_in, default_con_out, default_span_data.EOL)
|
||||||
add_fiber_padding(network, fibers, padding)
|
add_fiber_padding(network, fibers, padding)
|
||||||
# don't group split fiber and add amp in the same loop
|
# don't group split fiber and add amp in the same loop
|
||||||
# =>for code clarity (at the expense of speed):
|
# =>for code clarity (at the expense of speed):
|
||||||
@@ -423,6 +547,7 @@ def build_network(network, equipment, pref_ch_db, pref_total_db):
|
|||||||
|
|
||||||
amplified_nodes = [n for n in network.nodes()
|
amplified_nodes = [n for n in network.nodes()
|
||||||
if isinstance(n, Fiber) or isinstance(n, Roadm)]
|
if isinstance(n, Fiber) or isinstance(n, Roadm)]
|
||||||
|
|
||||||
for node in amplified_nodes:
|
for node in amplified_nodes:
|
||||||
add_egress_amplifier(network, node)
|
add_egress_amplifier(network, node)
|
||||||
|
|
||||||
@@ -436,3 +561,11 @@ def build_network(network, equipment, pref_ch_db, pref_total_db):
|
|||||||
for t in trx:
|
for t in trx:
|
||||||
set_egress_amplifier(network, t, equipment, pref_total_db)
|
set_egress_amplifier(network, t, equipment, pref_total_db)
|
||||||
|
|
||||||
|
def load_sim_params(filename):
|
||||||
|
sim_params = load_json(filename)
|
||||||
|
return SimParams(params=sim_params)
|
||||||
|
|
||||||
|
def configure_network(network, sim_params):
|
||||||
|
for node in network.nodes:
|
||||||
|
if isinstance(node, RamanFiber):
|
||||||
|
node.sim_params = sim_params
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ gnpy.core.node
|
|||||||
This module contains the base class for a network element.
|
This module contains the base class for a network element.
|
||||||
|
|
||||||
Strictly, a network element is any callable which accepts an immutable
|
Strictly, a network element is any callable which accepts an immutable
|
||||||
.info.SpectralInformation object and returns a .info.SpectralInformation object
|
:class:`.info.SpectralInformation` object and returns an :class:`.info.SpectralInformation` object
|
||||||
(a copy.)
|
(a copy).
|
||||||
|
|
||||||
Network elements MUST implement two attributes .uid and .name representing a
|
Network elements MUST implement two attributes .uid and .name representing a
|
||||||
unique identifier and a printable name.
|
unique identifier and a printable name.
|
||||||
|
|
||||||
This base class provides a mode convenient way to define a network element
|
This base class provides a more convenient way to define a network element
|
||||||
via subclassing.
|
via subclassing.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -26,10 +26,12 @@ class Location(namedtuple('Location', 'latitude longitude city region')):
|
|||||||
return super().__new__(cls, latitude, longitude, city, region)
|
return super().__new__(cls, latitude, longitude, city, region)
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
def __init__(self, uid, name=None, params=None, metadata={'location':{}}, operational=None):
|
def __init__(self, uid, name=None, params=None, metadata=None, operational=None):
|
||||||
if name is None:
|
if name is None:
|
||||||
name = uid
|
name = uid
|
||||||
self.uid, self.name = uid, name
|
self.uid, self.name = uid, name
|
||||||
|
if metadata is None:
|
||||||
|
metadata = {'location': {}}
|
||||||
if metadata and not isinstance(metadata.get('location'), Location):
|
if metadata and not isinstance(metadata.get('location'), Location):
|
||||||
metadata['location'] = Location(**metadata.pop('location', {}))
|
metadata['location'] = Location(**metadata.pop('location', {}))
|
||||||
self.params, self.metadata, self.operational = params, metadata, operational
|
self.params, self.metadata, self.operational = params, metadata, operational
|
||||||
|
|||||||
1000
gnpy/core/request.py
1000
gnpy/core/request.py
File diff suppressed because it is too large
Load Diff
820
gnpy/core/science_utils.py
Normal file
820
gnpy/core/science_utils.py
Normal file
@@ -0,0 +1,820 @@
|
|||||||
|
import numpy as np
|
||||||
|
from operator import attrgetter
|
||||||
|
from collections import namedtuple
|
||||||
|
from logging import getLogger
|
||||||
|
import scipy.constants as ph
|
||||||
|
from scipy.integrate import solve_bvp
|
||||||
|
from scipy.integrate import cumtrapz
|
||||||
|
from scipy.interpolate import interp1d
|
||||||
|
from scipy.optimize import OptimizeResult
|
||||||
|
|
||||||
|
from gnpy.core.utils import db2lin
|
||||||
|
|
||||||
|
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class RamanParams():
|
||||||
|
def __init__(self, params):
|
||||||
|
self._flag_raman = params['flag_raman']
|
||||||
|
self._space_resolution = params['space_resolution']
|
||||||
|
self._tolerance = params['tolerance']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def flag_raman(self):
|
||||||
|
return self._flag_raman
|
||||||
|
|
||||||
|
@property
|
||||||
|
def space_resolution(self):
|
||||||
|
return self._space_resolution
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tolerance(self):
|
||||||
|
return self._tolerance
|
||||||
|
|
||||||
|
class NLIParams():
|
||||||
|
def __init__(self, params):
|
||||||
|
self._nli_method_name = params['nli_method_name']
|
||||||
|
self._wdm_grid_size = params['wdm_grid_size']
|
||||||
|
self._dispersion_tolerance = params['dispersion_tolerance']
|
||||||
|
self._phase_shift_tollerance = params['phase_shift_tollerance']
|
||||||
|
self._f_cut_resolution = None
|
||||||
|
self._f_pump_resolution = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nli_method_name(self):
|
||||||
|
return self._nli_method_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wdm_grid_size(self):
|
||||||
|
return self._wdm_grid_size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dispersion_tolerance(self):
|
||||||
|
return self._dispersion_tolerance
|
||||||
|
|
||||||
|
@property
|
||||||
|
def phase_shift_tollerance(self):
|
||||||
|
return self._phase_shift_tollerance
|
||||||
|
|
||||||
|
@property
|
||||||
|
def f_cut_resolution(self):
|
||||||
|
return self._f_cut_resolution
|
||||||
|
|
||||||
|
@f_cut_resolution.setter
|
||||||
|
def f_cut_resolution(self, f_cut_resolution):
|
||||||
|
self._f_cut_resolution = f_cut_resolution
|
||||||
|
|
||||||
|
@property
|
||||||
|
def f_pump_resolution(self):
|
||||||
|
return self._f_pump_resolution
|
||||||
|
|
||||||
|
@f_pump_resolution.setter
|
||||||
|
def f_pump_resolution(self, f_pump_resolution):
|
||||||
|
self._f_pump_resolution = f_pump_resolution
|
||||||
|
|
||||||
|
class SimParams():
|
||||||
|
def __init__(self, params):
|
||||||
|
self._raman_computed_channels = params['raman_computed_channels']
|
||||||
|
self._raman_params = RamanParams(params=params['raman_parameters'])
|
||||||
|
self._nli_params = NLIParams(params=params['nli_parameters'])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raman_computed_channels(self):
|
||||||
|
return self._raman_computed_channels
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raman_params(self):
|
||||||
|
return self._raman_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nli_params(self):
|
||||||
|
return self._nli_params
|
||||||
|
|
||||||
|
class FiberParams():
|
||||||
|
def __init__(self, fiber):
|
||||||
|
self._loss_coef = 2 * fiber.dbkm_2_lin()[1]
|
||||||
|
self._length = fiber.length
|
||||||
|
self._gamma = fiber.gamma
|
||||||
|
self._beta2 = fiber.beta2()
|
||||||
|
self._beta3 = fiber.beta3 if hasattr(fiber, 'beta3') else 0
|
||||||
|
self._f_ref_beta = fiber.f_ref_beta if hasattr(fiber, 'f_ref_beta') else 0
|
||||||
|
self._raman_efficiency = fiber.params.raman_efficiency
|
||||||
|
self._temperature = fiber.operational['temperature']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def loss_coef(self):
|
||||||
|
return self._loss_coef
|
||||||
|
|
||||||
|
@property
|
||||||
|
def length(self):
|
||||||
|
return self._length
|
||||||
|
|
||||||
|
@property
|
||||||
|
def gamma(self):
|
||||||
|
return self._gamma
|
||||||
|
|
||||||
|
@property
|
||||||
|
def beta2(self):
|
||||||
|
return self._beta2
|
||||||
|
|
||||||
|
@property
|
||||||
|
def beta3(self):
|
||||||
|
return self._beta3
|
||||||
|
|
||||||
|
@property
|
||||||
|
def f_ref_beta(self):
|
||||||
|
return self._f_ref_beta
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raman_efficiency(self):
|
||||||
|
return self._raman_efficiency
|
||||||
|
|
||||||
|
@property
|
||||||
|
def temperature(self):
|
||||||
|
return self._temperature
|
||||||
|
|
||||||
|
def alpha0(self, f_ref=193.5e12):
|
||||||
|
""" It returns the zero element of the series expansion of attenuation coefficient alpha(f) in the
|
||||||
|
reference frequency f_ref
|
||||||
|
|
||||||
|
:param f_ref: reference frequency of series expansion [Hz]
|
||||||
|
:return: alpha0: power attenuation coefficient in f_ref [Neper/m]
|
||||||
|
"""
|
||||||
|
if not hasattr(self.loss_coef, 'alpha_power'):
|
||||||
|
alpha0 = self.loss_coef
|
||||||
|
else:
|
||||||
|
alpha_interp = interp1d(self.loss_coef['frequency'],
|
||||||
|
self.loss_coef['alpha_power'])
|
||||||
|
alpha0 = alpha_interp(f_ref)
|
||||||
|
return alpha0
|
||||||
|
|
||||||
|
pump = namedtuple('RamanPump', 'power frequency propagation_direction')
|
||||||
|
|
||||||
|
def propagate_raman_fiber(fiber, *carriers):
|
||||||
|
sim_params = fiber.sim_params
|
||||||
|
raman_params = fiber.sim_params.raman_params
|
||||||
|
nli_params = fiber.sim_params.nli_params
|
||||||
|
# apply input attenuation to carriers
|
||||||
|
attenuation_in = db2lin(fiber.con_in + fiber.att_in)
|
||||||
|
chan = []
|
||||||
|
for carrier in carriers:
|
||||||
|
pwr = carrier.power
|
||||||
|
pwr = pwr._replace(signal=pwr.signal / attenuation_in,
|
||||||
|
nli=pwr.nli / attenuation_in,
|
||||||
|
ase=pwr.ase / attenuation_in)
|
||||||
|
carrier = carrier._replace(power=pwr)
|
||||||
|
chan.append(carrier)
|
||||||
|
carriers = tuple(f for f in chan)
|
||||||
|
fiber_params = FiberParams(fiber)
|
||||||
|
|
||||||
|
# evaluate fiber attenuation involving also SRS if required by sim_params
|
||||||
|
if 'raman_pumps' in fiber.operational:
|
||||||
|
raman_pumps = tuple(pump(p['power'], p['frequency'], p['propagation_direction'])
|
||||||
|
for p in fiber.operational['raman_pumps'])
|
||||||
|
else:
|
||||||
|
raman_pumps = None
|
||||||
|
raman_solver = RamanSolver(raman_params=raman_params, fiber_params=fiber_params)
|
||||||
|
stimulated_raman_scattering = raman_solver.stimulated_raman_scattering(carriers=carriers,
|
||||||
|
raman_pumps=raman_pumps)
|
||||||
|
fiber_attenuation = (stimulated_raman_scattering.rho[:, -1])**-2
|
||||||
|
if not raman_params.flag_raman:
|
||||||
|
fiber_attenuation = tuple(fiber.lin_attenuation for _ in carriers)
|
||||||
|
|
||||||
|
# evaluate Raman ASE noise if required by sim_params and if raman pumps are present
|
||||||
|
if raman_params.flag_raman and raman_pumps:
|
||||||
|
raman_ase = raman_solver.spontaneous_raman_scattering.power[:, -1]
|
||||||
|
else:
|
||||||
|
raman_ase = tuple(0 for _ in carriers)
|
||||||
|
|
||||||
|
# evaluate nli and propagate in fiber
|
||||||
|
attenuation_out = db2lin(fiber.con_out)
|
||||||
|
nli_solver = NliSolver(nli_params=nli_params, fiber_params=fiber_params)
|
||||||
|
nli_solver.stimulated_raman_scattering = stimulated_raman_scattering
|
||||||
|
|
||||||
|
nli_frequencies = []
|
||||||
|
computed_nli = []
|
||||||
|
for carrier in (c for c in carriers if c.channel_number in sim_params.raman_computed_channels):
|
||||||
|
resolution_param = frequency_resolution(carrier, carriers, sim_params, fiber_params)
|
||||||
|
f_cut_resolution, f_pump_resolution, _, _ = resolution_param
|
||||||
|
nli_params.f_cut_resolution = f_cut_resolution
|
||||||
|
nli_params.f_pump_resolution = f_pump_resolution
|
||||||
|
nli_frequencies.append(carrier.frequency)
|
||||||
|
computed_nli.append(nli_solver.compute_nli(carrier, *carriers))
|
||||||
|
|
||||||
|
new_carriers = []
|
||||||
|
for carrier, attenuation, rmn_ase in zip(carriers, fiber_attenuation, raman_ase):
|
||||||
|
carrier_nli = np.interp(carrier.frequency, nli_frequencies, computed_nli)
|
||||||
|
pwr = carrier.power
|
||||||
|
pwr = pwr._replace(signal=pwr.signal/attenuation/attenuation_out,
|
||||||
|
nli=(pwr.nli+carrier_nli)/attenuation/attenuation_out,
|
||||||
|
ase=((pwr.ase/attenuation)+rmn_ase)/attenuation_out)
|
||||||
|
new_carriers.append(carrier._replace(power=pwr))
|
||||||
|
return new_carriers
|
||||||
|
|
||||||
|
def frequency_resolution(carrier, carriers, sim_params, fiber_params):
|
||||||
|
def _get_freq_res_k_phi(delta_count, grid_size, alpha0, delta_z, beta2, k_tol, phi_tol):
|
||||||
|
res_phi = _get_freq_res_phase_rotation(delta_count, grid_size, delta_z, beta2, phi_tol)
|
||||||
|
res_k = _get_freq_res_dispersion_attenuation(delta_count, grid_size, alpha0, beta2, k_tol)
|
||||||
|
res_dict = {'res_phi': res_phi, 'res_k': res_k}
|
||||||
|
method = min(res_dict, key=res_dict.get)
|
||||||
|
return res_dict[method], method, res_dict
|
||||||
|
|
||||||
|
def _get_freq_res_dispersion_attenuation(delta_count, grid_size, alpha0, beta2, k_tol):
|
||||||
|
return k_tol * abs(alpha0) / abs(beta2) / (1 + delta_count) / (4 * np.pi ** 2 * grid_size)
|
||||||
|
|
||||||
|
def _get_freq_res_phase_rotation(delta_count, grid_size, delta_z, beta2, phi_tol):
|
||||||
|
return phi_tol / abs(beta2) / (1 + delta_count) / delta_z / (4 * np.pi ** 2 * grid_size)
|
||||||
|
|
||||||
|
grid_size = sim_params.nli_params.wdm_grid_size
|
||||||
|
delta_z = sim_params.raman_params.space_resolution
|
||||||
|
alpha0 = fiber_params.alpha0()
|
||||||
|
beta2 = fiber_params.beta2
|
||||||
|
k_tol = sim_params.nli_params.dispersion_tolerance
|
||||||
|
phi_tol = sim_params.nli_params.phase_shift_tollerance
|
||||||
|
f_pump_resolution, method_f_pump, res_dict_pump = \
|
||||||
|
_get_freq_res_k_phi(0, grid_size, alpha0, delta_z, beta2, k_tol, phi_tol)
|
||||||
|
f_cut_resolution = {}
|
||||||
|
method_f_cut = {}
|
||||||
|
res_dict_cut = {}
|
||||||
|
for cut_carrier in carriers:
|
||||||
|
delta_number = cut_carrier.channel_number - carrier.channel_number
|
||||||
|
delta_count = abs(delta_number)
|
||||||
|
f_res, method, res_dict = \
|
||||||
|
_get_freq_res_k_phi(delta_count, grid_size, alpha0, delta_z, beta2, k_tol, phi_tol)
|
||||||
|
f_cut_resolution[f'delta_{delta_number}'] = f_res
|
||||||
|
method_f_cut[delta_number] = method
|
||||||
|
res_dict_cut[delta_number] = res_dict
|
||||||
|
return [f_cut_resolution, f_pump_resolution, (method_f_cut, method_f_pump), (res_dict_cut, res_dict_pump)]
|
||||||
|
|
||||||
|
def raised_cosine_comb(f, *carriers):
|
||||||
|
""" Returns an array storing the PSD of a WDM comb of raised cosine shaped
|
||||||
|
channels at the input frequencies defined in array f
|
||||||
|
:param f: numpy array of frequencies in Hz
|
||||||
|
:param carriers: namedtuple describing the WDM comb
|
||||||
|
:return: PSD of the WDM comb evaluated over f
|
||||||
|
"""
|
||||||
|
psd = np.zeros(np.shape(f))
|
||||||
|
for carrier in carriers:
|
||||||
|
f_nch = carrier.frequency
|
||||||
|
g_ch = carrier.power.signal / carrier.baud_rate
|
||||||
|
ts = 1 / carrier.baud_rate
|
||||||
|
passband = (1 - carrier.roll_off) / (2 / carrier.baud_rate)
|
||||||
|
stopband = (1 + carrier.roll_off) / (2 / carrier.baud_rate)
|
||||||
|
ff = np.abs(f - f_nch)
|
||||||
|
tf = ff - passband
|
||||||
|
if carrier.roll_off == 0:
|
||||||
|
psd = np.where(tf <= 0, g_ch, 0.) + psd
|
||||||
|
else:
|
||||||
|
psd = g_ch * (np.where(tf <= 0, 1., 0.) + 1 / 2 * (1 + np.cos(np.pi * ts / carrier.roll_off * tf)) *
|
||||||
|
np.where(tf > 0, 1., 0.) * np.where(np.abs(ff) <= stopband, 1., 0.)) + psd
|
||||||
|
return psd
|
||||||
|
|
||||||
|
class RamanSolver:
|
||||||
|
def __init__(self, raman_params=None, fiber_params=None):
|
||||||
|
""" Initialize the fiber object with its physical parameters
|
||||||
|
:param length: fiber length in m.
|
||||||
|
:param alphap: fiber power attenuation coefficient vs frequency in 1/m. numpy array
|
||||||
|
:param freq_alpha: frequency axis of alphap in Hz. numpy array
|
||||||
|
:param cr_raman: Raman efficiency vs frequency offset in 1/W/m. numpy array
|
||||||
|
:param freq_cr: reference frequency offset axis for cr_raman. numpy array
|
||||||
|
:param raman_params: namedtuple containing the solver parameters (optional).
|
||||||
|
"""
|
||||||
|
self.fiber_params = fiber_params
|
||||||
|
self.raman_params = raman_params
|
||||||
|
self._carriers = None
|
||||||
|
self._stimulated_raman_scattering = None
|
||||||
|
self._spontaneous_raman_scattering = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fiber_params(self):
|
||||||
|
return self._fiber_params
|
||||||
|
|
||||||
|
@fiber_params.setter
|
||||||
|
def fiber_params(self, fiber_params):
|
||||||
|
self._stimulated_raman_scattering = None
|
||||||
|
self._fiber_params = fiber_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def carriers(self):
|
||||||
|
return self._carriers
|
||||||
|
|
||||||
|
@carriers.setter
|
||||||
|
def carriers(self, carriers):
|
||||||
|
"""
|
||||||
|
:param carriers: tuple of namedtuples containing information about carriers
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self._carriers = carriers
|
||||||
|
self._stimulated_raman_scattering = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raman_pumps(self):
|
||||||
|
return self._raman_pumps
|
||||||
|
|
||||||
|
@raman_pumps.setter
|
||||||
|
def raman_pumps(self, raman_pumps):
|
||||||
|
self._raman_pumps = raman_pumps
|
||||||
|
self._stimulated_raman_scattering = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raman_params(self):
|
||||||
|
return self._raman_params
|
||||||
|
|
||||||
|
@raman_params.setter
|
||||||
|
def raman_params(self, raman_params):
|
||||||
|
"""
|
||||||
|
:param raman_params: namedtuple containing the solver parameters (optional).
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self._raman_params = raman_params
|
||||||
|
self._stimulated_raman_scattering = None
|
||||||
|
self._spontaneous_raman_scattering = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def spontaneous_raman_scattering(self):
|
||||||
|
if self._spontaneous_raman_scattering is None:
|
||||||
|
# SET STUFF
|
||||||
|
loss_coef = self.fiber_params.loss_coef
|
||||||
|
raman_efficiency = self.fiber_params.raman_efficiency
|
||||||
|
temperature = self.fiber_params.temperature
|
||||||
|
carriers = self.carriers
|
||||||
|
raman_pumps = self.raman_pumps
|
||||||
|
|
||||||
|
logger.debug('Start computing fiber Spontaneous Raman Scattering')
|
||||||
|
power_spectrum, freq_array, prop_direct, bn_array = self._compute_power_spectrum(carriers, raman_pumps)
|
||||||
|
|
||||||
|
if not hasattr(loss_coef, 'alpha_power'):
|
||||||
|
alphap_fiber = loss_coef * np.ones(freq_array.shape)
|
||||||
|
else:
|
||||||
|
interp_alphap = interp1d(loss_coef['frequency'], loss_coef['alpha_power'])
|
||||||
|
alphap_fiber = interp_alphap(freq_array)
|
||||||
|
|
||||||
|
freq_diff = abs(freq_array - np.reshape(freq_array, (len(freq_array), 1)))
|
||||||
|
interp_cr = interp1d(raman_efficiency['frequency_offset'], raman_efficiency['cr'])
|
||||||
|
cr = interp_cr(freq_diff)
|
||||||
|
|
||||||
|
# z propagation axis
|
||||||
|
z_array = self._stimulated_raman_scattering.z
|
||||||
|
ase_bc = np.zeros(freq_array.shape)
|
||||||
|
|
||||||
|
# calculate ase power
|
||||||
|
spontaneous_raman_scattering = self._int_spontaneous_raman(z_array, self._stimulated_raman_scattering.power,
|
||||||
|
alphap_fiber, freq_array, cr, freq_diff, ase_bc,
|
||||||
|
bn_array, temperature)
|
||||||
|
|
||||||
|
setattr(spontaneous_raman_scattering, 'frequency', freq_array)
|
||||||
|
setattr(spontaneous_raman_scattering, 'z', z_array)
|
||||||
|
setattr(spontaneous_raman_scattering, 'power', spontaneous_raman_scattering.x)
|
||||||
|
delattr(spontaneous_raman_scattering, 'x')
|
||||||
|
|
||||||
|
logger.debug(spontaneous_raman_scattering.message)
|
||||||
|
|
||||||
|
self._spontaneous_raman_scattering = spontaneous_raman_scattering
|
||||||
|
|
||||||
|
return self._spontaneous_raman_scattering
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _compute_power_spectrum(carriers, raman_pumps=None):
|
||||||
|
"""
|
||||||
|
Rearrangement of spectral and Raman pump information to make them compatible with Raman solver
|
||||||
|
:param carriers: a tuple of namedtuples describing the transmitted channels
|
||||||
|
:param raman_pumps: a namedtuple describing the Raman pumps
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Signal power spectrum
|
||||||
|
pow_array = np.array([])
|
||||||
|
f_array = np.array([])
|
||||||
|
noise_bandwidth_array = np.array([])
|
||||||
|
for carrier in sorted(carriers, key=attrgetter('frequency')):
|
||||||
|
f_array = np.append(f_array, carrier.frequency)
|
||||||
|
pow_array = np.append(pow_array, carrier.power.signal)
|
||||||
|
ref_bw = carrier.baud_rate
|
||||||
|
noise_bandwidth_array = np.append(noise_bandwidth_array, ref_bw)
|
||||||
|
|
||||||
|
propagation_direction = np.ones(len(f_array))
|
||||||
|
|
||||||
|
# Raman pump power spectrum
|
||||||
|
if raman_pumps:
|
||||||
|
for pump in raman_pumps:
|
||||||
|
pow_array = np.append(pow_array, pump.power)
|
||||||
|
f_array = np.append(f_array, pump.frequency)
|
||||||
|
direction = +1 if pump.propagation_direction.lower() == 'coprop' else -1
|
||||||
|
propagation_direction = np.append(propagation_direction, direction)
|
||||||
|
noise_bandwidth_array = np.append(noise_bandwidth_array, ref_bw)
|
||||||
|
|
||||||
|
# Final sorting
|
||||||
|
ind = np.argsort(f_array)
|
||||||
|
f_array = f_array[ind]
|
||||||
|
pow_array = pow_array[ind]
|
||||||
|
propagation_direction = propagation_direction[ind]
|
||||||
|
|
||||||
|
return pow_array, f_array, propagation_direction, noise_bandwidth_array
|
||||||
|
|
||||||
|
def _int_spontaneous_raman(self, z_array, raman_matrix, alphap_fiber, freq_array, cr_raman_matrix, freq_diff, ase_bc, bn_array, temperature):
|
||||||
|
spontaneous_raman_scattering = OptimizeResult()
|
||||||
|
|
||||||
|
dx = self.raman_params.space_resolution
|
||||||
|
h = ph.value('Planck constant')
|
||||||
|
kb = ph.value('Boltzmann constant')
|
||||||
|
|
||||||
|
power_ase = np.nan * np.ones(raman_matrix.shape)
|
||||||
|
int_pump = cumtrapz(raman_matrix, z_array, dx=dx, axis=1, initial=0)
|
||||||
|
|
||||||
|
for f_ind, f_ase in enumerate(freq_array):
|
||||||
|
cr_raman = cr_raman_matrix[f_ind, :]
|
||||||
|
vibrational_loss = f_ase / freq_array[:f_ind]
|
||||||
|
eta = 1/(np.exp((h*freq_diff[f_ind, f_ind+1:])/(kb*temperature)) - 1)
|
||||||
|
|
||||||
|
int_fiber_loss = -alphap_fiber[f_ind] * z_array
|
||||||
|
int_raman_loss = np.sum((cr_raman[:f_ind] * vibrational_loss * int_pump[:f_ind, :].transpose()).transpose(), axis=0)
|
||||||
|
int_raman_gain = np.sum((cr_raman[f_ind + 1:] * int_pump[f_ind + 1:, :].transpose()).transpose(), axis=0)
|
||||||
|
|
||||||
|
int_gain_loss = int_fiber_loss + int_raman_gain + int_raman_loss
|
||||||
|
|
||||||
|
new_ase = np.sum((cr_raman[f_ind+1:] * (1 + eta) * raman_matrix[f_ind+1:, :].transpose()).transpose() * h * f_ase * bn_array[f_ind], axis=0)
|
||||||
|
|
||||||
|
bc_evolution = ase_bc[f_ind] * np.exp(int_gain_loss)
|
||||||
|
ase_evolution = np.exp(int_gain_loss) * cumtrapz(new_ase*np.exp(-int_gain_loss), z_array, dx=dx, initial=0)
|
||||||
|
|
||||||
|
power_ase[f_ind, :] = bc_evolution + ase_evolution
|
||||||
|
|
||||||
|
spontaneous_raman_scattering.x = 2 * power_ase
|
||||||
|
spontaneous_raman_scattering.success = True
|
||||||
|
spontaneous_raman_scattering.message = "Spontaneous Raman Scattering evaluated successfully"
|
||||||
|
|
||||||
|
return spontaneous_raman_scattering
|
||||||
|
|
||||||
|
def stimulated_raman_scattering(self, carriers, raman_pumps=None):
|
||||||
|
""" Returns stimulated Raman scattering solution including
|
||||||
|
fiber gain/loss profile.
|
||||||
|
:return: self._stimulated_raman_scattering: the SRS problem solution.
|
||||||
|
scipy.interpolate.PPoly instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self._stimulated_raman_scattering is None:
|
||||||
|
# fiber parameters
|
||||||
|
fiber_length = self.fiber_params.length
|
||||||
|
loss_coef = self.fiber_params.loss_coef
|
||||||
|
if self.raman_params.flag_raman:
|
||||||
|
raman_efficiency = self.fiber_params.raman_efficiency
|
||||||
|
else:
|
||||||
|
raman_efficiency = self.fiber_params.raman_efficiency
|
||||||
|
raman_efficiency['cr'] = np.array(raman_efficiency['cr']) * 0
|
||||||
|
# raman solver parameters
|
||||||
|
z_resolution = self.raman_params.space_resolution
|
||||||
|
tolerance = self.raman_params.tolerance
|
||||||
|
|
||||||
|
logger.debug('Start computing fiber Stimulated Raman Scattering')
|
||||||
|
|
||||||
|
power_spectrum, freq_array, prop_direct, _ = self._compute_power_spectrum(carriers, raman_pumps)
|
||||||
|
|
||||||
|
if not hasattr(loss_coef, 'alpha_power'):
|
||||||
|
alphap_fiber = loss_coef * np.ones(freq_array.shape)
|
||||||
|
else:
|
||||||
|
interp_alphap = interp1d(loss_coef['frequency'], loss_coef['alpha_power'])
|
||||||
|
alphap_fiber = interp_alphap(freq_array)
|
||||||
|
|
||||||
|
freq_diff = abs(freq_array - np.reshape(freq_array, (len(freq_array), 1)))
|
||||||
|
interp_cr = interp1d(raman_efficiency['frequency_offset'], raman_efficiency['cr'])
|
||||||
|
cr = interp_cr(freq_diff)
|
||||||
|
|
||||||
|
# z propagation axis
|
||||||
|
z = np.arange(0, fiber_length+1, z_resolution)
|
||||||
|
|
||||||
|
ode_function = lambda z, p: self._ode_stimulated_raman(z, p, alphap_fiber, freq_array, cr, prop_direct)
|
||||||
|
boundary_residual = lambda ya, yb: self._residuals_stimulated_raman(ya, yb, power_spectrum, prop_direct)
|
||||||
|
initial_guess_conditions = self._initial_guess_stimulated_raman(z, power_spectrum, alphap_fiber, prop_direct)
|
||||||
|
|
||||||
|
# ODE SOLVER
|
||||||
|
stimulated_raman_scattering = solve_bvp(ode_function, boundary_residual, z, initial_guess_conditions, tol=tolerance)
|
||||||
|
|
||||||
|
rho = (stimulated_raman_scattering.y.transpose() / power_spectrum).transpose()
|
||||||
|
rho = np.sqrt(rho) # From power attenuation to field attenuation
|
||||||
|
setattr(stimulated_raman_scattering, 'frequency', freq_array)
|
||||||
|
setattr(stimulated_raman_scattering, 'z', stimulated_raman_scattering.x)
|
||||||
|
setattr(stimulated_raman_scattering, 'rho', rho)
|
||||||
|
setattr(stimulated_raman_scattering, 'power', stimulated_raman_scattering.y)
|
||||||
|
delattr(stimulated_raman_scattering, 'x')
|
||||||
|
delattr(stimulated_raman_scattering, 'y')
|
||||||
|
|
||||||
|
self.carriers = carriers
|
||||||
|
self.raman_pumps = raman_pumps
|
||||||
|
self._stimulated_raman_scattering = stimulated_raman_scattering
|
||||||
|
|
||||||
|
return self._stimulated_raman_scattering
|
||||||
|
|
||||||
|
def _residuals_stimulated_raman(self, ya, yb, power_spectrum, prop_direct):
|
||||||
|
|
||||||
|
computed_boundary_value = np.zeros(ya.size)
|
||||||
|
|
||||||
|
for index, direction in enumerate(prop_direct):
|
||||||
|
if direction == +1:
|
||||||
|
computed_boundary_value[index] = ya[index]
|
||||||
|
else:
|
||||||
|
computed_boundary_value[index] = yb[index]
|
||||||
|
|
||||||
|
return power_spectrum - computed_boundary_value
|
||||||
|
|
||||||
|
def _initial_guess_stimulated_raman(self, z, power_spectrum, alphap_fiber, prop_direct):
|
||||||
|
""" Computes the initial guess knowing the boundary conditions
|
||||||
|
:param z: patial axis [m]. numpy array
|
||||||
|
:param power_spectrum: power in each frequency slice [W]. Frequency axis is defined by freq_array. numpy array
|
||||||
|
:param alphap_fiber: frequency dependent fiber attenuation of signal power [1/m]. Frequency defined by freq_array. numpy array
|
||||||
|
:param prop_direct: indicates the propagation direction of each power slice in power_spectrum:
|
||||||
|
+1 for forward propagation and -1 for backward propagation. Frequency defined by freq_array. numpy array
|
||||||
|
:return: power_guess: guess on the initial conditions [W]. The first ndarray index identifies the frequency slice,
|
||||||
|
the second ndarray index identifies the step in z. ndarray
|
||||||
|
"""
|
||||||
|
|
||||||
|
power_guess = np.empty((power_spectrum.size, z.size))
|
||||||
|
for f_index, power_slice in enumerate(power_spectrum):
|
||||||
|
if prop_direct[f_index] == +1:
|
||||||
|
power_guess[f_index, :] = np.exp(-alphap_fiber[f_index] * z) * power_slice
|
||||||
|
else:
|
||||||
|
power_guess[f_index, :] = np.exp(-alphap_fiber[f_index] * z[::-1]) * power_slice
|
||||||
|
|
||||||
|
return power_guess
|
||||||
|
|
||||||
|
def _ode_stimulated_raman(self, z, power_spectrum, alphap_fiber, freq_array, cr_raman_matrix, prop_direct):
|
||||||
|
""" Aim of ode_raman is to implement the set of ordinary differential equations (ODEs) describing the Raman effect.
|
||||||
|
:param z: spatial axis (unused).
|
||||||
|
:param power_spectrum: power in each frequency slice [W]. Frequency axis is defined by freq_array. numpy array. Size n
|
||||||
|
:param alphap_fiber: frequency dependent fiber attenuation of signal power [1/m]. Frequency defined by freq_array. numpy array. Size n
|
||||||
|
:param freq_array: reference frequency axis [Hz]. numpy array. Size n
|
||||||
|
:param cr_raman: Cr(f) Raman gain efficiency variation in frequency [1/W/m]. Frequency defined by freq_array. numpy ndarray. Size nxn
|
||||||
|
:param prop_direct: indicates the propagation direction of each power slice in power_spectrum:
|
||||||
|
+1 for forward propagation and -1 for backward propagation. Frequency defined by freq_array. numpy array. Size n
|
||||||
|
:return: dP/dz: the power variation in dz [W/m]. numpy array. Size n
|
||||||
|
"""
|
||||||
|
|
||||||
|
dpdz = np.nan * np.ones(power_spectrum.shape)
|
||||||
|
for f_ind, power in enumerate(power_spectrum):
|
||||||
|
cr_raman = cr_raman_matrix[f_ind, :]
|
||||||
|
vibrational_loss = freq_array[f_ind] / freq_array[:f_ind]
|
||||||
|
|
||||||
|
for z_ind, power_sample in enumerate(power):
|
||||||
|
raman_gain = np.sum(cr_raman[f_ind+1:] * power_spectrum[f_ind+1:, z_ind])
|
||||||
|
raman_loss = np.sum(vibrational_loss * cr_raman[:f_ind] * power_spectrum[:f_ind, z_ind])
|
||||||
|
|
||||||
|
dpdz_element = prop_direct[f_ind] * (-alphap_fiber[f_ind] + raman_gain - raman_loss) * power_sample
|
||||||
|
dpdz[f_ind][z_ind] = dpdz_element
|
||||||
|
|
||||||
|
return np.vstack(dpdz)
|
||||||
|
|
||||||
|
class NliSolver:
|
||||||
|
""" This class implements the NLI models.
|
||||||
|
Model and method can be specified in `self.nli_params.method`.
|
||||||
|
List of implemented methods:
|
||||||
|
'gn_model_analytic': brute force triple integral solution
|
||||||
|
'ggn_spectrally_separated_xpm_spm': XPM plus SPM
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, nli_params=None, fiber_params=None):
|
||||||
|
""" Initialize the fiber object with its physical parameters
|
||||||
|
"""
|
||||||
|
self.fiber_params = fiber_params
|
||||||
|
self.nli_params = nli_params
|
||||||
|
self.stimulated_raman_scattering = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fiber_params(self):
|
||||||
|
return self._fiber_params
|
||||||
|
|
||||||
|
@fiber_params.setter
|
||||||
|
def fiber_params(self, fiber_params):
|
||||||
|
self._fiber_params = fiber_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stimulated_raman_scattering(self):
|
||||||
|
return self._stimulated_raman_scattering
|
||||||
|
|
||||||
|
@stimulated_raman_scattering.setter
|
||||||
|
def stimulated_raman_scattering(self, stimulated_raman_scattering):
|
||||||
|
self._stimulated_raman_scattering = stimulated_raman_scattering
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nli_params(self):
|
||||||
|
return self._nli_params
|
||||||
|
|
||||||
|
@nli_params.setter
|
||||||
|
def nli_params(self, nli_params):
|
||||||
|
"""
|
||||||
|
:param model_params: namedtuple containing the parameters used to compute the NLI.
|
||||||
|
"""
|
||||||
|
self._nli_params = nli_params
|
||||||
|
|
||||||
|
def compute_nli(self, carrier, *carriers):
|
||||||
|
""" Compute NLI power generated by the WDM comb `*carriers` on the channel under test `carrier`
|
||||||
|
at the end of the fiber span.
|
||||||
|
"""
|
||||||
|
if 'gn_model_analytic' == self.nli_params.nli_method_name.lower():
|
||||||
|
carrier_nli = self._gn_analytic(carrier, *carriers)
|
||||||
|
elif 'ggn_spectrally_separated' in self.nli_params.nli_method_name.lower():
|
||||||
|
eta_matrix = self._compute_eta_matrix(carrier, *carriers)
|
||||||
|
carrier_nli = self._carrier_nli_from_eta_matrix(eta_matrix, carrier, *carriers)
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Method {self.nli_params.method_nli} not implemented.')
|
||||||
|
|
||||||
|
return carrier_nli
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _carrier_nli_from_eta_matrix(eta_matrix, carrier, *carriers):
|
||||||
|
carrier_nli = 0
|
||||||
|
for pump_carrier_1 in carriers:
|
||||||
|
for pump_carrier_2 in carriers:
|
||||||
|
carrier_nli += eta_matrix[pump_carrier_1.channel_number-1, pump_carrier_2.channel_number-1] * \
|
||||||
|
pump_carrier_1.power.signal * pump_carrier_2.power.signal
|
||||||
|
carrier_nli *= carrier.power.signal
|
||||||
|
|
||||||
|
return carrier_nli
|
||||||
|
|
||||||
|
def _compute_eta_matrix(self, carrier_cut, *carriers):
|
||||||
|
cut_index = carrier_cut.channel_number - 1
|
||||||
|
# Matrix initialization
|
||||||
|
matrix_size = max(carriers, key=lambda x: getattr(x, 'channel_number')).channel_number
|
||||||
|
eta_matrix = np.zeros(shape=(matrix_size, matrix_size))
|
||||||
|
|
||||||
|
# SPM
|
||||||
|
logger.debug(f'Start computing SPM on channel #{carrier_cut.channel_number}')
|
||||||
|
# SPM GGN
|
||||||
|
if 'ggn' in self.nli_params.nli_method_name.lower():
|
||||||
|
partial_nli = self._generalized_spectrally_separated_spm(carrier_cut)
|
||||||
|
# SPM GN
|
||||||
|
elif 'gn' in self.nli_params.nli_method_name.lower():
|
||||||
|
partial_nli = self._gn_analytic(carrier_cut, *[carrier_cut])
|
||||||
|
eta_matrix[cut_index, cut_index] = partial_nli / (carrier_cut.power.signal**3)
|
||||||
|
|
||||||
|
# XPM
|
||||||
|
for pump_carrier in carriers:
|
||||||
|
pump_index = pump_carrier.channel_number - 1
|
||||||
|
if not (cut_index == pump_index):
|
||||||
|
logger.debug(f'Start computing XPM on channel #{carrier_cut.channel_number} '
|
||||||
|
f'from channel #{pump_carrier.channel_number}')
|
||||||
|
# XPM GGN
|
||||||
|
if 'ggn' in self.nli_params.nli_method_name.lower():
|
||||||
|
partial_nli = self._generalized_spectrally_separated_xpm(carrier_cut, pump_carrier)
|
||||||
|
# XPM GGN
|
||||||
|
elif 'gn' in self.nli_params.nli_method_name.lower():
|
||||||
|
partial_nli = self._gn_analytic(carrier_cut, *[pump_carrier])
|
||||||
|
eta_matrix[pump_index, pump_index] = partial_nli /\
|
||||||
|
(carrier_cut.power.signal * pump_carrier.power.signal**2)
|
||||||
|
return eta_matrix
|
||||||
|
|
||||||
|
# Methods for computing GN-model
|
||||||
|
def _gn_analytic(self, carrier, *carriers):
|
||||||
|
""" Computes the nonlinear interference power on a single carrier.
|
||||||
|
The method uses eq. 120 from arXiv:1209.0394.
|
||||||
|
:param carrier: the signal under analysis
|
||||||
|
:param carriers: the full WDM comb
|
||||||
|
:return: carrier_nli: the amount of nonlinear interference in W on the carrier under analysis
|
||||||
|
"""
|
||||||
|
alpha = self.fiber_params.alpha0() / 2
|
||||||
|
beta2 = self.fiber_params.beta2
|
||||||
|
gamma = self.fiber_params.gamma
|
||||||
|
length = self.fiber_params.length
|
||||||
|
effective_length = (1 - np.exp(-2 * alpha * length)) / (2 * alpha)
|
||||||
|
asymptotic_length = 1 / (2 * alpha)
|
||||||
|
|
||||||
|
g_nli = 0
|
||||||
|
for interfering_carrier in carriers:
|
||||||
|
g_interfearing = interfering_carrier.power.signal / interfering_carrier.baud_rate
|
||||||
|
g_signal = carrier.power.signal / carrier.baud_rate
|
||||||
|
g_nli += g_interfearing**2 * g_signal \
|
||||||
|
* _psi(carrier, interfering_carrier, beta2=self.fiber_params.beta2, asymptotic_length=1/self.fiber_params.alpha0())
|
||||||
|
g_nli *= (16.0 / 27.0) * (gamma * effective_length)**2 /\
|
||||||
|
(2 * np.pi * abs(beta2) * asymptotic_length)
|
||||||
|
carrier_nli = carrier.baud_rate * g_nli
|
||||||
|
return carrier_nli
|
||||||
|
|
||||||
|
# Methods for computing the GGN-model
|
||||||
|
def _generalized_spectrally_separated_spm(self, carrier):
|
||||||
|
f_cut_resolution = self.nli_params.f_cut_resolution['delta_0']
|
||||||
|
f_eval = carrier.frequency
|
||||||
|
g_cut = (carrier.power.signal / carrier.baud_rate)
|
||||||
|
|
||||||
|
spm_nli = carrier.baud_rate * (16.0 / 27.0) * self.fiber_params.gamma**2 * g_cut**3 * \
|
||||||
|
self._generalized_psi(carrier, carrier, f_eval, f_cut_resolution, f_cut_resolution)
|
||||||
|
return spm_nli
|
||||||
|
|
||||||
|
def _generalized_spectrally_separated_xpm(self, carrier_cut, pump_carrier):
|
||||||
|
delta_index = pump_carrier.channel_number - carrier_cut.channel_number
|
||||||
|
f_cut_resolution = self.nli_params.f_cut_resolution[f'delta_{delta_index}']
|
||||||
|
f_pump_resolution = self.nli_params.f_pump_resolution
|
||||||
|
f_eval = carrier_cut.frequency
|
||||||
|
g_pump = (pump_carrier.power.signal / pump_carrier.baud_rate)
|
||||||
|
g_cut = (carrier_cut.power.signal / carrier_cut.baud_rate)
|
||||||
|
frequency_offset_threshold = self._frequency_offset_threshold(pump_carrier.baud_rate)
|
||||||
|
if abs(carrier_cut.frequency - pump_carrier.frequency) <= frequency_offset_threshold:
|
||||||
|
xpm_nli = carrier_cut.baud_rate * (16.0 / 27.0) * self.fiber_params.gamma**2 * g_pump**2 * g_cut * \
|
||||||
|
2 * self._generalized_psi(carrier_cut, pump_carrier, f_eval, f_cut_resolution, f_pump_resolution)
|
||||||
|
else:
|
||||||
|
xpm_nli = carrier_cut.baud_rate * (16.0 / 27.0) * self.fiber_params.gamma**2 * g_pump**2 * g_cut * \
|
||||||
|
2 * self._fast_generalized_psi(carrier_cut, pump_carrier, f_eval, f_cut_resolution)
|
||||||
|
return xpm_nli
|
||||||
|
|
||||||
|
def _fast_generalized_psi(self, carrier_cut, pump_carrier, f_eval, f_cut_resolution):
|
||||||
|
""" It computes the generalized psi function similarly to the one used in the GN model
|
||||||
|
:return: generalized_psi
|
||||||
|
"""
|
||||||
|
# Fiber parameters
|
||||||
|
alpha0 = self.fiber_params.alpha0(f_eval)
|
||||||
|
beta2 = self.fiber_params.beta2
|
||||||
|
beta3 = self.fiber_params.beta3
|
||||||
|
f_ref_beta = self.fiber_params.f_ref_beta
|
||||||
|
z = self.stimulated_raman_scattering.z
|
||||||
|
frequency_rho = self.stimulated_raman_scattering.frequency
|
||||||
|
rho_norm = self.stimulated_raman_scattering.rho * np.exp(np.abs(alpha0) * z / 2)
|
||||||
|
if len(frequency_rho) == 1:
|
||||||
|
rho_function = lambda f: rho_norm[0, :]
|
||||||
|
else:
|
||||||
|
rho_function = interp1d(frequency_rho, rho_norm, axis=0, fill_value='extrapolate')
|
||||||
|
rho_norm_pump = rho_function(pump_carrier.frequency)
|
||||||
|
|
||||||
|
f1_array = np.array([pump_carrier.frequency - (pump_carrier.baud_rate * (1 + pump_carrier.roll_off) / 2),
|
||||||
|
pump_carrier.frequency + (pump_carrier.baud_rate * (1 + pump_carrier.roll_off) / 2)])
|
||||||
|
f2_array = np.arange(carrier_cut.frequency,
|
||||||
|
carrier_cut.frequency + (carrier_cut.baud_rate * (1 + carrier_cut.roll_off) / 2),
|
||||||
|
f_cut_resolution) # Only positive f2 is used since integrand_f2 is symmetric
|
||||||
|
|
||||||
|
integrand_f1 = np.zeros(len(f1_array))
|
||||||
|
for f1_index, f1 in enumerate(f1_array):
|
||||||
|
delta_beta = 4 * np.pi**2 * (f1 - f_eval) * (f2_array - f_eval) * \
|
||||||
|
(beta2 + np.pi * beta3 * (f1 + f2_array - 2 * f_ref_beta))
|
||||||
|
integrand_f2 = self._generalized_rho_nli(delta_beta, rho_norm_pump, z, alpha0)
|
||||||
|
integrand_f1[f1_index] = 2 * np.trapz(integrand_f2, f2_array) # 2x since integrand_f2 is symmetric in f2
|
||||||
|
generalized_psi = 0.5 * sum(integrand_f1) * pump_carrier.baud_rate
|
||||||
|
return generalized_psi
|
||||||
|
|
||||||
|
def _generalized_psi(self, carrier_cut, pump_carrier, f_eval, f_cut_resolution, f_pump_resolution):
|
||||||
|
""" It computes the generalized psi function similarly to the one used in the GN model
|
||||||
|
:return: generalized_psi
|
||||||
|
"""
|
||||||
|
# Fiber parameters
|
||||||
|
alpha0 = self.fiber_params.alpha0(f_eval)
|
||||||
|
beta2 = self.fiber_params.beta2
|
||||||
|
beta3 = self.fiber_params.beta3
|
||||||
|
f_ref_beta = self.fiber_params.f_ref_beta
|
||||||
|
z = self.stimulated_raman_scattering.z
|
||||||
|
frequency_rho = self.stimulated_raman_scattering.frequency
|
||||||
|
rho_norm = self.stimulated_raman_scattering.rho * np.exp(np.abs(alpha0) * z / 2)
|
||||||
|
if len(frequency_rho) == 1:
|
||||||
|
rho_function = lambda f: rho_norm[0, :]
|
||||||
|
else:
|
||||||
|
rho_function = interp1d(frequency_rho, rho_norm, axis=0, fill_value='extrapolate')
|
||||||
|
rho_norm_pump = rho_function(pump_carrier.frequency)
|
||||||
|
|
||||||
|
f1_array = np.arange(pump_carrier.frequency - (pump_carrier.baud_rate * (1 + pump_carrier.roll_off) / 2),
|
||||||
|
pump_carrier.frequency + (pump_carrier.baud_rate * (1 + pump_carrier.roll_off) / 2),
|
||||||
|
f_pump_resolution)
|
||||||
|
f2_array = np.arange(carrier_cut.frequency - (carrier_cut.baud_rate * (1 + carrier_cut.roll_off) / 2),
|
||||||
|
carrier_cut.frequency + (carrier_cut.baud_rate * (1 + carrier_cut.roll_off) / 2),
|
||||||
|
f_cut_resolution)
|
||||||
|
psd1 = raised_cosine_comb(f1_array, pump_carrier) * (pump_carrier.baud_rate / pump_carrier.power.signal)
|
||||||
|
|
||||||
|
integrand_f1 = np.zeros(len(f1_array))
|
||||||
|
for f1_index, (f1, psd1_sample) in enumerate(zip(f1_array, psd1)):
|
||||||
|
f3_array = f1 + f2_array - f_eval
|
||||||
|
psd2 = raised_cosine_comb(f2_array, carrier_cut) * (carrier_cut.baud_rate / carrier_cut.power.signal)
|
||||||
|
psd3 = raised_cosine_comb(f3_array, pump_carrier) * (pump_carrier.baud_rate / pump_carrier.power.signal)
|
||||||
|
ggg = psd1_sample * psd2 * psd3
|
||||||
|
|
||||||
|
delta_beta = 4 * np.pi**2 * (f1 - f_eval) * (f2_array - f_eval) * \
|
||||||
|
(beta2 + np.pi * beta3 * (f1 + f2_array - 2 * f_ref_beta))
|
||||||
|
|
||||||
|
integrand_f2 = ggg * self._generalized_rho_nli(delta_beta, rho_norm_pump, z, alpha0)
|
||||||
|
integrand_f1[f1_index] = np.trapz(integrand_f2, f2_array)
|
||||||
|
generalized_psi = np.trapz(integrand_f1, f1_array)
|
||||||
|
return generalized_psi
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _generalized_rho_nli(delta_beta, rho_norm_pump, z, alpha0):
|
||||||
|
w = 1j * delta_beta - alpha0
|
||||||
|
generalized_rho_nli = (rho_norm_pump[-1]**2 * np.exp(w * z[-1]) - rho_norm_pump[0]**2 * np.exp(w * z[0])) / w
|
||||||
|
for z_ind in range(0, len(z) - 1):
|
||||||
|
derivative_rho = (rho_norm_pump[z_ind + 1]**2 - rho_norm_pump[z_ind]**2) / (z[z_ind + 1] - z[z_ind])
|
||||||
|
generalized_rho_nli -= derivative_rho * (np.exp(w * z[z_ind + 1]) - np.exp(w * z[z_ind])) / (w**2)
|
||||||
|
generalized_rho_nli = np.abs(generalized_rho_nli)**2
|
||||||
|
return generalized_rho_nli
|
||||||
|
|
||||||
|
def _frequency_offset_threshold(self, symbol_rate):
|
||||||
|
k_ref = 5
|
||||||
|
beta2_ref = 21.3e-27
|
||||||
|
delta_f_ref = 50e9
|
||||||
|
rs_ref = 32e9
|
||||||
|
freq_offset_th = ((k_ref * delta_f_ref) * rs_ref * beta2_ref) / (self.fiber_params.beta2 * symbol_rate)
|
||||||
|
return freq_offset_th
|
||||||
|
|
||||||
|
def _psi(carrier, interfering_carrier, beta2, asymptotic_length):
|
||||||
|
"""Calculates eq. 123 from `arXiv:1209.0394 <https://arxiv.org/abs/1209.0394>`__"""
|
||||||
|
|
||||||
|
if carrier.channel_number == interfering_carrier.channel_number: # SCI, SPM
|
||||||
|
psi = np.arcsinh(0.5 * np.pi**2 * asymptotic_length * abs(beta2) * carrier.baud_rate**2)
|
||||||
|
else: # XCI, XPM
|
||||||
|
delta_f = carrier.frequency - interfering_carrier.frequency
|
||||||
|
psi = np.arcsinh(np.pi**2 * asymptotic_length * abs(beta2) *
|
||||||
|
carrier.baud_rate * (delta_f + 0.5 * interfering_carrier.baud_rate))
|
||||||
|
psi -= np.arcsinh(np.pi**2 * asymptotic_length * abs(beta2) *
|
||||||
|
carrier.baud_rate * (delta_f - 0.5 * interfering_carrier.baud_rate))
|
||||||
|
return psi
|
||||||
@@ -22,6 +22,7 @@ from json import dumps
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from gnpy.core.equipment import load_equipment
|
from gnpy.core.equipment import load_equipment
|
||||||
from gnpy.core.utils import db2lin, lin2db
|
from gnpy.core.utils import db2lin, lin2db
|
||||||
|
from gnpy.core.exceptions import ServiceError
|
||||||
|
|
||||||
SERVICES_COLUMN = 12
|
SERVICES_COLUMN = 12
|
||||||
#EQPT_LIBRARY_FILENAME = Path(__file__).parent / 'eqpt_config.json'
|
#EQPT_LIBRARY_FILENAME = Path(__file__).parent / 'eqpt_config.json'
|
||||||
@@ -43,17 +44,18 @@ class Element:
|
|||||||
return hash((type(self), self.uid))
|
return hash((type(self), self.uid))
|
||||||
|
|
||||||
class Request_element(Element):
|
class Request_element(Element):
|
||||||
def __init__(self,Request,eqpt_filename):
|
def __init__(self, Request, eqpt_filename, bidir):
|
||||||
# request_id is str
|
# request_id is str
|
||||||
# excel has automatic number formatting that adds .0 on integer values
|
# excel has automatic number formatting that adds .0 on integer values
|
||||||
# the next lines recover the pure int value, assuming this .0 is unwanted
|
# the next lines recover the pure int value, assuming this .0 is unwanted
|
||||||
self.request_id = correct_xlrd_int_to_str_reading(Request.request_id)
|
self.request_id = correct_xlrd_int_to_str_reading(Request.request_id)
|
||||||
self.source = Request.source
|
self.source = f'trx {Request.source}'
|
||||||
self.destination = Request.destination
|
self.destination = f'trx {Request.destination}'
|
||||||
# TODO: the automatic naming generated by excel parser requires that source and dest name
|
# TODO: the automatic naming generated by excel parser requires that source and dest name
|
||||||
# be a string starting with 'trx' : this is manually added here.
|
# be a string starting with 'trx' : this is manually added here.
|
||||||
self.srctpid = f'trx {Request.source}'
|
self.srctpid = f'trx {Request.source}'
|
||||||
self.dsttpid = f'trx {Request.destination}'
|
self.dsttpid = f'trx {Request.destination}'
|
||||||
|
self.bidir = bidir
|
||||||
# test that trx_type belongs to eqpt_config.json
|
# test that trx_type belongs to eqpt_config.json
|
||||||
# if not replace it with a default
|
# if not replace it with a default
|
||||||
equipment = load_equipment(eqpt_filename)
|
equipment = load_equipment(eqpt_filename)
|
||||||
@@ -73,17 +75,17 @@ class Request_element(Element):
|
|||||||
Requestmode = None
|
Requestmode = None
|
||||||
self.mode = Request.mode
|
self.mode = Request.mode
|
||||||
except KeyError:
|
except KeyError:
|
||||||
msg = f'Request Id: {self.request_id} - could not find tsp : \'{Request.trx_type}\' with mode: \'{Requestmode}\' in eqpt library \nComputation stopped.'
|
msg = f'Request Id: {self.request_id} - could not find tsp : \'{Request.trx_type}\' with mode: \'{Request.mode}\' in eqpt library \nComputation stopped.'
|
||||||
#print(msg)
|
#print(msg)
|
||||||
logger.critical(msg)
|
logger.critical(msg)
|
||||||
exit()
|
raise ServiceError(msg)
|
||||||
# excel input are in GHz and dBm
|
# excel input are in GHz and dBm
|
||||||
if Request.spacing is not None:
|
if Request.spacing is not None:
|
||||||
self.spacing = Request.spacing * 1e9
|
self.spacing = Request.spacing * 1e9
|
||||||
else:
|
else:
|
||||||
msg = f'Request {self.request_id} missing spacing: spacing is mandatory.\ncomputation stopped'
|
msg = f'Request {self.request_id} missing spacing: spacing is mandatory.\ncomputation stopped'
|
||||||
logger.critical(msg)
|
logger.critical(msg)
|
||||||
exit()
|
raise ServiceError(msg)
|
||||||
if Request.power is not None:
|
if Request.power is not None:
|
||||||
self.power = db2lin(Request.power) * 1e-3
|
self.power = db2lin(Request.power) * 1e-3
|
||||||
else:
|
else:
|
||||||
@@ -120,9 +122,9 @@ class Request_element(Element):
|
|||||||
|
|
||||||
# the excel parser applies the same hop-type to all nodes in the route nodes_list.
|
# the excel parser applies the same hop-type to all nodes in the route nodes_list.
|
||||||
# user can change this per node in the generated json
|
# user can change this per node in the generated json
|
||||||
self.loose = 'loose'
|
self.loose = 'LOOSE'
|
||||||
if Request.is_loose == 'no' :
|
if Request.is_loose == 'no' :
|
||||||
self.loose = 'strict'
|
self.loose = 'STRICT'
|
||||||
self.path_bandwidth = None
|
self.path_bandwidth = None
|
||||||
if Request.path_bandwidth is not None:
|
if Request.path_bandwidth is not None:
|
||||||
self.path_bandwidth = Request.path_bandwidth * 1e9
|
self.path_bandwidth = Request.path_bandwidth * 1e9
|
||||||
@@ -132,46 +134,41 @@ class Request_element(Element):
|
|||||||
uid = property(lambda self: repr(self))
|
uid = property(lambda self: repr(self))
|
||||||
@property
|
@property
|
||||||
def pathrequest(self):
|
def pathrequest(self):
|
||||||
|
# Default assumption for bidir is False
|
||||||
req_dictionnary = {
|
req_dictionnary = {
|
||||||
'request-id':self.request_id,
|
'request-id':self.request_id,
|
||||||
'source': self.source,
|
'source': self.source,
|
||||||
'destination': self.destination,
|
'destination': self.destination,
|
||||||
'src-tp-id': self.srctpid,
|
'src-tp-id': self.srctpid,
|
||||||
'dst-tp-id': self.dsttpid,
|
'dst-tp-id': self.dsttpid,
|
||||||
|
'bidirectional': self.bidir,
|
||||||
'path-constraints':{
|
'path-constraints':{
|
||||||
'te-bandwidth': {
|
'te-bandwidth': {
|
||||||
'technology': 'flexi-grid',
|
'technology': 'flexi-grid',
|
||||||
'trx_type' : self.trx_type,
|
'trx_type' : self.trx_type,
|
||||||
'trx_mode' : self.mode,
|
'trx_mode' : self.mode,
|
||||||
'effective-freq-slot':[{'n': 'null','m': 'null'}] ,
|
'effective-freq-slot':[{'N': 'null', 'M': 'null'}],
|
||||||
'spacing' : self.spacing,
|
'spacing' : self.spacing,
|
||||||
'max-nb-of-channel' : self.nb_channel,
|
'max-nb-of-channel' : self.nb_channel,
|
||||||
'output-power' : self.power
|
'output-power' : self.power
|
||||||
# 'path_bandwidth' : self.path_bandwidth
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
'optimizations': {
|
}
|
||||||
'explicit-route-include-objects': [
|
|
||||||
{
|
if self.nodes_list:
|
||||||
|
req_dictionnary['explicit-route-objects'] = {}
|
||||||
|
temp = {'route-object-include-exclude' : [
|
||||||
|
{'explicit-route-usage': 'route-include-ero',
|
||||||
'index': self.nodes_list.index(node),
|
'index': self.nodes_list.index(node),
|
||||||
'unnumbered-hop':{
|
'num-unnum-hop': {
|
||||||
'node-id': f'{node}',
|
'node-id': f'{node}',
|
||||||
'link-tp-id': 'link-tp-id is not used',
|
'link-tp-id': 'link-tp-id is not used',
|
||||||
'hop-type': f'{self.loose}',
|
'hop-type': f'{self.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]
|
||||||
}
|
}
|
||||||
for node in self.nodes_list
|
req_dictionnary['explicit-route-objects'] = temp
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.path_bandwidth is not None:
|
if self.path_bandwidth is not None:
|
||||||
req_dictionnary['path-constraints']['te-bandwidth']['path_bandwidth'] = self.path_bandwidth
|
req_dictionnary['path-constraints']['te-bandwidth']['path_bandwidth'] = self.path_bandwidth
|
||||||
|
|
||||||
@@ -181,30 +178,41 @@ class Request_element(Element):
|
|||||||
if self.disjoint_from :
|
if self.disjoint_from :
|
||||||
return {'synchronization-id':self.request_id,
|
return {'synchronization-id':self.request_id,
|
||||||
'svec': {
|
'svec': {
|
||||||
'relaxable' : 'False',
|
'relaxable' : 'false',
|
||||||
'link-diverse': 'True',
|
'disjointness': 'node link',
|
||||||
'node-diverse': 'True',
|
|
||||||
'request-id-number': [self.request_id]+ [n for n in self.disjoint_from]
|
'request-id-number': [self.request_id]+ [n for n in self.disjoint_from]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else:
|
||||||
|
return None
|
||||||
# TO-DO: avoid multiple entries with same synchronisation vectors
|
# TO-DO: avoid multiple entries with same synchronisation vectors
|
||||||
@property
|
@property
|
||||||
def json(self):
|
def json(self):
|
||||||
return self.pathrequest , self.pathsync
|
return self.pathrequest , self.pathsync
|
||||||
|
|
||||||
def convert_service_sheet(input_filename, eqpt_filename, output_filename='', filter_region=[]):
|
def convert_service_sheet(input_filename, eqpt_filename, output_filename='', bidir=False, filter_region=None):
|
||||||
|
""" converts a service sheet into a json structure
|
||||||
|
"""
|
||||||
|
if filter_region is None:
|
||||||
|
filter_region = []
|
||||||
service = parse_excel(input_filename)
|
service = parse_excel(input_filename)
|
||||||
req = [Request_element(n,eqpt_filename) for n in service]
|
req = [Request_element(n, eqpt_filename, bidir) for n in service]
|
||||||
# dumps the output into a json file with name
|
# dumps the output into a json file with name
|
||||||
# split_filename = [input_filename[0:len(input_filename)-len(suffix_filename)] , suffix_filename[1:]]
|
# split_filename = [input_filename[0:len(input_filename)-len(suffix_filename)] , suffix_filename[1:]]
|
||||||
if output_filename=='':
|
if output_filename=='':
|
||||||
output_filename = f'{str(input_filename)[0:len(str(input_filename))-len(str(input_filename.suffixes[0]))]}_services.json'
|
output_filename = f'{str(input_filename)[0:len(str(input_filename))-len(str(input_filename.suffixes[0]))]}_services.json'
|
||||||
# for debug
|
# for debug
|
||||||
# print(json_filename)
|
# print(json_filename)
|
||||||
|
# if there is no sync vector , do not write any synchronization
|
||||||
|
synchro = [n.json[1] for n in req if n.json[1] is not None]
|
||||||
|
if synchro:
|
||||||
data = {
|
data = {
|
||||||
'path-request': [n.json[0] for n in req],
|
'path-request': [n.json[0] for n in req],
|
||||||
'synchronization': [n.json[1] for n in req
|
'synchronization': synchro
|
||||||
if n.json[1] is not None]
|
}
|
||||||
|
else:
|
||||||
|
data = {
|
||||||
|
'path-request': [n.json[0] for n in req]
|
||||||
}
|
}
|
||||||
with open(output_filename, 'w', encoding='utf-8') as f:
|
with open(output_filename, 'w', encoding='utf-8') as f:
|
||||||
f.write(dumps(data, indent=2, ensure_ascii=False))
|
f.write(dumps(data, indent=2, ensure_ascii=False))
|
||||||
@@ -232,16 +240,20 @@ def parse_excel(input_filename):
|
|||||||
return services
|
return services
|
||||||
|
|
||||||
def parse_service_sheet(service_sheet):
|
def parse_service_sheet(service_sheet):
|
||||||
|
""" reads each column according to authorized fieldnames. order is not important.
|
||||||
|
"""
|
||||||
logger.info(f'Validating headers on {service_sheet.name!r}')
|
logger.info(f'Validating headers on {service_sheet.name!r}')
|
||||||
# add a test on field to enable the '' field case that arises when columns on the
|
# add a test on field to enable the '' field case that arises when columns on the
|
||||||
# right hand side are used as comments or drawing in the excel sheet
|
# right hand side are used as comments or drawing in the excel sheet
|
||||||
header = [x.value.strip() for x in service_sheet.row(4)[0:SERVICES_COLUMN] if len(x.value.strip())>0]
|
header = [x.value.strip() for x in service_sheet.row(4)[0:SERVICES_COLUMN]
|
||||||
|
if len(x.value.strip()) > 0]
|
||||||
|
|
||||||
# create a service_fieldname independant from the excel column order
|
# create a service_fieldname independant from the excel column order
|
||||||
# to be compatible with any version of the sheet
|
# to be compatible with any version of the sheet
|
||||||
# the following dictionnary records the excel field names and the corresponding parameter's name
|
# the following dictionnary records the excel field names and the corresponding parameter's name
|
||||||
|
|
||||||
authorized_fieldnames = {'route id':'request_id', 'Source':'source', 'Destination':'destination', \
|
authorized_fieldnames = {
|
||||||
|
'route id':'request_id', 'Source':'source', 'Destination':'destination', \
|
||||||
'TRX type':'trx_type', 'Mode' : 'mode', 'System: spacing':'spacing', \
|
'TRX type':'trx_type', 'Mode' : 'mode', 'System: spacing':'spacing', \
|
||||||
'System: input power (dBm)':'power', 'System: nb of channels':'nb_channel',\
|
'System: input power (dBm)':'power', 'System: nb of channels':'nb_channel',\
|
||||||
'routing: disjoint from': 'disjoint_from', 'routing: path':'nodes_list',\
|
'routing: disjoint from': 'disjoint_from', 'routing: path':'nodes_list',\
|
||||||
|
|||||||
386
gnpy/core/spectrum_assignment.py
Normal file
386
gnpy/core/spectrum_assignment.py
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
gnpy.core.spectrum_assignment
|
||||||
|
=============================
|
||||||
|
|
||||||
|
This module contains the Oms and Bitmap classes and the different method to
|
||||||
|
select and assign spectrum. Spectrum_selection function identifies the free
|
||||||
|
slots and select_candidate selects the candidate spectrum according to
|
||||||
|
strategy: for example first fit
|
||||||
|
oms records its elements, and elements are updated with an oms to have
|
||||||
|
element/oms correspondace
|
||||||
|
"""
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
from logging import getLogger
|
||||||
|
from math import ceil
|
||||||
|
from gnpy.core.elements import Roadm, Transceiver
|
||||||
|
from gnpy.core.exceptions import SpectrumError
|
||||||
|
|
||||||
|
LOGGER = getLogger(__name__)
|
||||||
|
|
||||||
|
class Bitmap:
|
||||||
|
""" records the spectrum occupation
|
||||||
|
"""
|
||||||
|
def __init__(self, f_min, f_max, grid, guardband=0.15e12, bitmap=None):
|
||||||
|
# n is the min index including guardband. Guardband is require to be sure
|
||||||
|
# that a channel can be assigned with center frequency fmin (means that its
|
||||||
|
# slot occupation goes below freq_index_min
|
||||||
|
n_min = frequency_to_n(f_min-guardband, grid)
|
||||||
|
n_max = frequency_to_n(f_max+guardband, grid) - 1
|
||||||
|
self.n_min = n_min
|
||||||
|
self.n_max = n_max
|
||||||
|
self.freq_index_min = frequency_to_n(f_min)
|
||||||
|
self.freq_index_max = frequency_to_n(f_max)
|
||||||
|
self.freq_index = list(range(n_min, n_max+1))
|
||||||
|
if bitmap is None:
|
||||||
|
self.bitmap = [1] * (n_max-n_min+1)
|
||||||
|
elif len(bitmap) == len(self.freq_index):
|
||||||
|
self.bitmap = bitmap
|
||||||
|
else:
|
||||||
|
raise SpectrumError(f'bitmap is not consistant with f_min{f_min} - n: {n_min} and f_max{f_max}- n :{n_max}')
|
||||||
|
|
||||||
|
def getn(self, i):
|
||||||
|
""" converts the n (itu grid) into a local index
|
||||||
|
"""
|
||||||
|
return self.freq_index[i]
|
||||||
|
def geti(self, nvalue):
|
||||||
|
""" converts the local index into n (itu grid)
|
||||||
|
"""
|
||||||
|
return self.freq_index.index(nvalue)
|
||||||
|
def insert_left(self, newbitmap):
|
||||||
|
""" insert bitmap on the left to align oms bitmaps if their start frequencies are different
|
||||||
|
"""
|
||||||
|
self.bitmap = newbitmap + self.bitmap
|
||||||
|
temp = list(range(self.n_min-len(newbitmap), self.n_min))
|
||||||
|
self.freq_index = temp + self.freq_index
|
||||||
|
self.n_min = self.freq_index[0]
|
||||||
|
def insert_right(self, newbitmap):
|
||||||
|
""" insert bitmap on the right to align oms bitmaps if their stop frequencies are different
|
||||||
|
"""
|
||||||
|
self.bitmap = self.bitmap + newbitmap
|
||||||
|
self.freq_index = self.freq_index + list(range(self.n_max, self.n_max+len(newbitmap)))
|
||||||
|
self.n_max = self.freq_index[-1]
|
||||||
|
|
||||||
|
# +'grid available_slots f_min f_max services_list')
|
||||||
|
OMSParams = namedtuple('OMSParams', 'oms_id el_id_list el_list')
|
||||||
|
|
||||||
|
class OMS:
|
||||||
|
""" OMS class is the logical container that represent a link between two adjacent ROADMs and
|
||||||
|
records the crossed elements and the occupied spectrum
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **params):
|
||||||
|
params = OMSParams(**params)
|
||||||
|
self.oms_id = params.oms_id
|
||||||
|
self.el_id_list = params.el_id_list
|
||||||
|
self.el_list = params.el_list
|
||||||
|
self.spectrum_bitmap = []
|
||||||
|
self.nb_channels = 0
|
||||||
|
self.service_list = []
|
||||||
|
# TODO
|
||||||
|
def __str__(self):
|
||||||
|
return '\n\t'.join([f'{type(self).__name__} {self.oms_id}',
|
||||||
|
f'{self.el_id_list[0]} - {self.el_id_list[-1]}'])
|
||||||
|
def __repr__(self):
|
||||||
|
return '\n\t'.join([f'{type(self).__name__} {self.oms_id}',
|
||||||
|
f'{self.el_id_list[0]} - {self.el_id_list[-1]}', '\n'])
|
||||||
|
|
||||||
|
def add_element(self, elem):
|
||||||
|
""" records oms elements
|
||||||
|
"""
|
||||||
|
self.el_id_list.append(elem.uid)
|
||||||
|
self.el_list.append(elem)
|
||||||
|
|
||||||
|
def update_spectrum(self, f_min, f_max, guardband=0.15e12, existing_spectrum=None,
|
||||||
|
grid=0.00625e12):
|
||||||
|
""" frequencies expressed in Hz
|
||||||
|
"""
|
||||||
|
if existing_spectrum is None:
|
||||||
|
# add some 150 GHz margin to enable a center channel on f_min
|
||||||
|
# use ITU-T G694.1
|
||||||
|
# Flexible DWDM grid definition
|
||||||
|
# For the flexible DWDM grid, the allowed frequency slots have a nominal
|
||||||
|
# central frequency (in THz) defined by:
|
||||||
|
# 193.1 + n × 0.00625 where n is a positive or negative integer including 0
|
||||||
|
# and 0.00625 is the nominal central frequency granularity in THz
|
||||||
|
# and a slot width defined by:
|
||||||
|
# 12.5 × m where m is a positive integer and 12.5 is the slot width granularity in
|
||||||
|
# GHz.
|
||||||
|
# Any combination of frequency slots is allowed as long as no two frequency
|
||||||
|
# slots overlap.
|
||||||
|
|
||||||
|
# TODO : add explaination on that / parametrize ....
|
||||||
|
self.spectrum_bitmap = Bitmap(f_min, f_max, grid, guardband)
|
||||||
|
# print(len(self.spectrum_bitmap.bitmap))
|
||||||
|
|
||||||
|
def assign_spectrum(self, nvalue, mvalue):
|
||||||
|
""" change oms spectrum to mark spectrum assigned
|
||||||
|
"""
|
||||||
|
if (nvalue is None or mvalue is None or isinstance(nvalue, float)
|
||||||
|
or isinstance(mvalue, float) or mvalue == 0):
|
||||||
|
raise SpectrumError('could not assign None values')
|
||||||
|
startn, stopn = mvalue_to_slots(nvalue, mvalue)
|
||||||
|
# print(f'startn stop n {startn} , {stopn}')
|
||||||
|
# assumes that guardbands are sufficient to ensure that assigning a center channel
|
||||||
|
# at fmin or fmax is OK is startn > self.spectrum_bitmap.n_min
|
||||||
|
if (nvalue <= self.spectrum_bitmap.freq_index_max and
|
||||||
|
nvalue >= self.spectrum_bitmap.freq_index_min and
|
||||||
|
stopn <= self.spectrum_bitmap.n_max and
|
||||||
|
startn > self.spectrum_bitmap.n_min):
|
||||||
|
# verification that both length are identical
|
||||||
|
self.spectrum_bitmap.bitmap[self.spectrum_bitmap.geti(startn):self.spectrum_bitmap.geti(stopn)+1] = [0] * (stopn-startn+1)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
msg = f'Could not assign n {nvalue}, m {mvalue} values:' +\
|
||||||
|
f' one or several slots are not available'
|
||||||
|
LOGGER.info(msg)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def add_service(self, service_id, nb_wl):
|
||||||
|
""" record service and mark spectrum as occupied
|
||||||
|
"""
|
||||||
|
self.service_list.append(service_id)
|
||||||
|
self.nb_channels += nb_wl
|
||||||
|
|
||||||
|
def frequency_to_n(freq, grid=0.00625e12):
|
||||||
|
""" converts frequency into the n value (ITU grid)
|
||||||
|
"""
|
||||||
|
return (int)((freq-193.1e12)/grid)
|
||||||
|
|
||||||
|
def nvalue_to_frequency(nvalue, grid=0.00625e12):
|
||||||
|
""" converts n value into a frequency
|
||||||
|
"""
|
||||||
|
return 193.1e12 + nvalue * grid
|
||||||
|
|
||||||
|
def mvalue_to_slots(nvalue, mvalue):
|
||||||
|
""" convert center n an m into start and stop n
|
||||||
|
"""
|
||||||
|
startn = nvalue - mvalue
|
||||||
|
stopn = nvalue + mvalue -1
|
||||||
|
return startn, stopn
|
||||||
|
|
||||||
|
def slots_to_m(startn, stopn):
|
||||||
|
""" converts the start and stop n values to the center n and m value
|
||||||
|
"""
|
||||||
|
nvalue = (int)((startn+stopn+1)/2)
|
||||||
|
mvalue = (int)((stopn-startn+1)/2)
|
||||||
|
return nvalue, mvalue
|
||||||
|
|
||||||
|
def m_to_freq(nvalue, mvalue, grid=0.00625e12):
|
||||||
|
""" converts m into frequency range
|
||||||
|
"""
|
||||||
|
startn, stopn = mvalue_to_slots(nvalue, mvalue)
|
||||||
|
fstart = nvalue_to_frequency(startn, grid)
|
||||||
|
fstop = nvalue_to_frequency(stopn+1, grid)
|
||||||
|
return fstart, fstop
|
||||||
|
|
||||||
|
def align_grids(oms_list):
|
||||||
|
""" used to apply same grid to all oms : same starting n, stop n and slot size
|
||||||
|
out of grid slots are set to 0
|
||||||
|
"""
|
||||||
|
n_min = min([o.spectrum_bitmap.n_min for o in oms_list])
|
||||||
|
n_max = max([o.spectrum_bitmap.n_max for o in oms_list])
|
||||||
|
for this_o in oms_list:
|
||||||
|
if (this_o.spectrum_bitmap.n_min - n_min) > 0:
|
||||||
|
this_o.spectrum_bitmap.insert_left([0] * (this_o.spectrum_bitmap.n_min - n_min))
|
||||||
|
if (n_max - this_o.spectrum_bitmap.n_max) > 0:
|
||||||
|
this_o.spectrum_bitmap.insert_right([0] * (n_max - this_o.spectrum_bitmap.n_max))
|
||||||
|
return oms_list
|
||||||
|
|
||||||
|
def build_oms_list(network, equipment):
|
||||||
|
""" initialization of OMS list in the network
|
||||||
|
an oms is build reading all intermediate nodes between two adjacent ROADMs
|
||||||
|
each element within the list is being added an oms and oms_id to record the
|
||||||
|
oms it belongs to.
|
||||||
|
the function supports different spectrum width and supposes that the whole network
|
||||||
|
works with the min range among OMSs
|
||||||
|
"""
|
||||||
|
oms_id = 0
|
||||||
|
oms_list = []
|
||||||
|
for node in [n for n in network.nodes() if isinstance(n, Roadm)]:
|
||||||
|
for edge in network.edges([node]):
|
||||||
|
if not isinstance(edge[1], Transceiver):
|
||||||
|
nd_in = edge[0] # nd_in is a Roadm
|
||||||
|
try:
|
||||||
|
nd_in.oms_list.append(oms_id)
|
||||||
|
except AttributeError:
|
||||||
|
nd_in.oms_list = []
|
||||||
|
nd_in.oms_list.append(oms_id)
|
||||||
|
nd_out = edge[1]
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
params['oms_id'] = oms_id
|
||||||
|
params['el_id_list'] = []
|
||||||
|
params['el_list'] = []
|
||||||
|
oms = OMS(**params)
|
||||||
|
oms.add_element(nd_in)
|
||||||
|
while not isinstance(nd_out, Roadm):
|
||||||
|
oms.add_element(nd_out)
|
||||||
|
# add an oms_id in the element
|
||||||
|
nd_out.oms_id = oms_id
|
||||||
|
nd_out.oms = oms
|
||||||
|
n_temp = nd_out
|
||||||
|
nd_out = next(n[1] for n in network.edges([n_temp]) if n[1].uid != nd_in.uid)
|
||||||
|
nd_in = n_temp
|
||||||
|
|
||||||
|
oms.add_element(nd_out)
|
||||||
|
# nd_out is a Roadm
|
||||||
|
try:
|
||||||
|
nd_out.oms_list.append(oms_id)
|
||||||
|
except AttributeError:
|
||||||
|
nd_out.oms_list = []
|
||||||
|
nd_out.oms_list.append(oms_id)
|
||||||
|
|
||||||
|
oms.update_spectrum(equipment['SI']['default'].f_min,
|
||||||
|
equipment['SI']['default'].f_max, grid=0.00625e12)
|
||||||
|
# oms.assign_spectrum(13,7) gives back (193137500000000.0, 193225000000000.0)
|
||||||
|
# as in the example in the standard
|
||||||
|
# oms.assign_spectrum(13,7)
|
||||||
|
|
||||||
|
oms_list.append(oms)
|
||||||
|
oms_id += 1
|
||||||
|
oms_list = align_grids(oms_list)
|
||||||
|
reversed_oms(oms_list)
|
||||||
|
return oms_list
|
||||||
|
|
||||||
|
def reversed_oms(oms_list):
|
||||||
|
""" identifies reversed OMS
|
||||||
|
only applicable for non parallel OMS
|
||||||
|
"""
|
||||||
|
for oms in oms_list:
|
||||||
|
has_reversed = False
|
||||||
|
for this_o in oms_list:
|
||||||
|
if (oms.el_id_list[0] == this_o.el_id_list[-1] and
|
||||||
|
oms.el_id_list[-1] == this_o.el_id_list[0]):
|
||||||
|
oms.reversed_oms = this_o
|
||||||
|
has_reversed = True
|
||||||
|
break
|
||||||
|
if not has_reversed:
|
||||||
|
oms.reversed_oms = None
|
||||||
|
|
||||||
|
|
||||||
|
def bitmap_sum(band1, band2):
|
||||||
|
""" a functions that marks occupied bitmap by 0 if the slot is occupied in band1 or in band2
|
||||||
|
"""
|
||||||
|
res = []
|
||||||
|
for i, elem in enumerate(band1):
|
||||||
|
if band2[i] * elem == 0:
|
||||||
|
res.append(0)
|
||||||
|
else:
|
||||||
|
res.append(1)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def spectrum_selection(pth, oms_list, requested_m, requested_n=None):
|
||||||
|
""" collects spectrum availability and call the select_candidate function
|
||||||
|
# step 1 collects pth spectrum availability
|
||||||
|
# step 2 if n is not None try to assign the spectrum
|
||||||
|
# if the spectrum is not available then sends back an "error"
|
||||||
|
# if n is None selects candidate spectrum
|
||||||
|
# select spectrum that fits the policy ( first fit, random, ABP...)
|
||||||
|
# step3 returns the selection
|
||||||
|
"""
|
||||||
|
|
||||||
|
# use indexes instead of ITU-T n values
|
||||||
|
path_oms = []
|
||||||
|
for elem in pth:
|
||||||
|
if not isinstance(elem, Roadm) and not isinstance(elem, Transceiver):
|
||||||
|
# only edfa, fused and fibers have oms_id attribute
|
||||||
|
path_oms.append(elem.oms_id)
|
||||||
|
# remove duplicate oms_id, order is not important
|
||||||
|
path_oms = list(set(path_oms))
|
||||||
|
# assuming all oms have same freq index
|
||||||
|
if not path_oms:
|
||||||
|
candidate = (None, None, None)
|
||||||
|
return candidate, path_oms
|
||||||
|
freq_index = oms_list[path_oms[0]].spectrum_bitmap.freq_index
|
||||||
|
freq_index_min = oms_list[path_oms[0]].spectrum_bitmap.freq_index_min
|
||||||
|
freq_index_max = oms_list[path_oms[0]].spectrum_bitmap.freq_index_max
|
||||||
|
|
||||||
|
freq_availability = oms_list[path_oms[0]].spectrum_bitmap.bitmap
|
||||||
|
for oms in path_oms[1:]:
|
||||||
|
freq_availability = bitmap_sum(oms_list[oms].spectrum_bitmap.bitmap, freq_availability)
|
||||||
|
if requested_n is None:
|
||||||
|
# avoid slots reserved on the edge 0.15e-12 on both sides -> 24
|
||||||
|
candidates = [(freq_index[i]+requested_m, freq_index[i], freq_index[i]+2*requested_m-1)
|
||||||
|
for i in range(len(freq_availability))
|
||||||
|
if freq_availability[i:i+2*requested_m] == [1] * (2*requested_m)
|
||||||
|
and freq_index[i] >= freq_index_min
|
||||||
|
and freq_index[i+2*requested_m-1] <= freq_index_max]
|
||||||
|
|
||||||
|
candidate = select_candidate(candidates, policy='first_fit')
|
||||||
|
else:
|
||||||
|
i = oms_list[path_oms[0]].spectrum_bitmap.geti(requested_n)
|
||||||
|
# print(f'N {requested_n} i {i}')
|
||||||
|
# print(freq_availability[i-m:i+m] )
|
||||||
|
# print(freq_index[i-m:i+m])
|
||||||
|
if (freq_availability[i-requested_m:i+requested_m] == [1] * (2*requested_m) and
|
||||||
|
freq_index[i-requested_m] >= freq_index_min
|
||||||
|
and freq_index[i+requested_m-1] <= freq_index_max):
|
||||||
|
# candidate is the triplet center_n, startn and stopn
|
||||||
|
candidate = (requested_n, requested_n-requested_m, requested_n+requested_m-1)
|
||||||
|
else:
|
||||||
|
candidate = (None, None, None)
|
||||||
|
# print("coucou11")
|
||||||
|
# print(candidate)
|
||||||
|
# print(freq_availability[321:321+2*m])
|
||||||
|
# a = [i+321 for i in range(2*m)]
|
||||||
|
# print(a)
|
||||||
|
# print(candidate)
|
||||||
|
return candidate, path_oms
|
||||||
|
|
||||||
|
def select_candidate(candidates, policy):
|
||||||
|
""" selects a candidate among all available spectrum
|
||||||
|
"""
|
||||||
|
if policy == 'first_fit':
|
||||||
|
if candidates:
|
||||||
|
return candidates[0]
|
||||||
|
else:
|
||||||
|
return (None, None, None)
|
||||||
|
else:
|
||||||
|
raise ServiceError('Only first_fit spectrum assignment policy is implemented.')
|
||||||
|
|
||||||
|
def pth_assign_spectrum(pths, rqs, oms_list, rpths):
|
||||||
|
""" basic first fit assignment
|
||||||
|
if reversed path are provided, means that occupation is bidir
|
||||||
|
"""
|
||||||
|
for i, pth in enumerate(pths):
|
||||||
|
# computes the number of channels required
|
||||||
|
try:
|
||||||
|
if rqs[i].blocking_reason:
|
||||||
|
rqs[i].blocked = True
|
||||||
|
rqs[i].N = 0
|
||||||
|
rqs[i].M = 0
|
||||||
|
except AttributeError:
|
||||||
|
nb_wl = ceil(rqs[i].path_bandwidth / rqs[i].bit_rate)
|
||||||
|
# computes the total nb of slots according to requested spacing
|
||||||
|
# TODO : express superchannels
|
||||||
|
# assumes that all channels must be grouped
|
||||||
|
# TODO : enables non contiguous reservation in case of blocking
|
||||||
|
requested_m = ceil(rqs[i].spacing / 0.0125e12) * nb_wl
|
||||||
|
# concatenate all path and reversed path elements to derive slots availability
|
||||||
|
(center_n, startn, stopn), path_oms = spectrum_selection(pth + rpths[i], oms_list, requested_m,
|
||||||
|
requested_n=None)
|
||||||
|
# checks that requested_m is fitting startm and stopm
|
||||||
|
# if not None, center_n and start, stop frequencies are applicable to all oms of pth
|
||||||
|
# checks that spectrum is not None else indicate blocking reason
|
||||||
|
if center_n is not None:
|
||||||
|
# checks that requested_m is fitting startm and stopm
|
||||||
|
if 2 * requested_m > (stopn - startn + 1):
|
||||||
|
msg = f'candidate: {(center_n, startn, stopn)} is not consistant ' +\
|
||||||
|
f'with {requested_m}'
|
||||||
|
LOGGER.critical(msg)
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
for oms_elem in path_oms:
|
||||||
|
oms_list[oms_elem].assign_spectrum(center_n, requested_m)
|
||||||
|
oms_list[oms_elem].add_service(rqs[i].request_id, nb_wl)
|
||||||
|
rqs[i].blocked = False
|
||||||
|
rqs[i].N = center_n
|
||||||
|
rqs[i].M = requested_m
|
||||||
|
else:
|
||||||
|
rqs[i].blocked = True
|
||||||
|
rqs[i].N = 0
|
||||||
|
rqs[i].M = 0
|
||||||
|
rqs[i].blocking_reason = 'NO_SPECTRUM'
|
||||||
@@ -11,8 +11,8 @@ This module contains utility functions that are used with gnpy.
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from csv import writer
|
from csv import writer
|
||||||
|
import numpy as np
|
||||||
from numpy import pi, cos, sqrt, log10
|
from numpy import pi, cos, sqrt, log10
|
||||||
from scipy import constants
|
from scipy import constants
|
||||||
|
|
||||||
@@ -73,21 +73,19 @@ def c():
|
|||||||
return constants.c
|
return constants.c
|
||||||
|
|
||||||
|
|
||||||
def itufs(spacing, startf=191.35, stopf=196.10):
|
def arrange_frequencies(length, start, stop):
|
||||||
"""Creates an array of frequencies whose default range is
|
"""Create an array of frequencies
|
||||||
191.35-196.10 THz
|
|
||||||
|
|
||||||
:param spacing: Frequency spacing in THz
|
:param length: number of elements
|
||||||
:param starf: Start frequency in THz
|
:param star: Start frequency in THz
|
||||||
:param stopf: Stop frequency in THz
|
:param stop: Stop frequency in THz
|
||||||
:type spacing: float
|
:type length: integer
|
||||||
:type startf: float
|
:type start: float
|
||||||
:type stopf: float
|
:type stop: float
|
||||||
:return an array of frequnecies determined by the spacing parameter
|
:return an array of frequencies determined by the spacing parameter
|
||||||
:rtype: numpy.ndarray
|
:rtype: numpy.ndarray
|
||||||
"""
|
"""
|
||||||
return np.arange(startf, stopf + spacing / 2, spacing)
|
return np.linspace(start, stop, length)
|
||||||
|
|
||||||
|
|
||||||
def h():
|
def h():
|
||||||
"""
|
"""
|
||||||
@@ -185,3 +183,43 @@ def rrc(ffs, baud_rate, alpha):
|
|||||||
p_inds = np.where(np.logical_and(np.abs(ffs) > 0, np.abs(ffs) < l_lim))
|
p_inds = np.where(np.logical_and(np.abs(ffs) > 0, np.abs(ffs) < l_lim))
|
||||||
hf[p_inds] = 1
|
hf[p_inds] = 1
|
||||||
return sqrt(hf)
|
return sqrt(hf)
|
||||||
|
|
||||||
|
def merge_amplifier_restrictions(dict1, dict2):
|
||||||
|
"""Updates contents of dicts recursively
|
||||||
|
|
||||||
|
>>> d1 = {'params': {'restrictions': {'preamp_variety_list': [], 'booster_variety_list': []}}}
|
||||||
|
>>> d2 = {'params': {'target_pch_out_db': -20}}
|
||||||
|
>>> merge_amplifier_restrictions(d1, d2)
|
||||||
|
{'params': {'restrictions': {'preamp_variety_list': [], 'booster_variety_list': []}, 'target_pch_out_db': -20}}
|
||||||
|
|
||||||
|
>>> d3 = {'params': {'restrictions': {'preamp_variety_list': ['foo'], 'booster_variety_list': ['bar']}}}
|
||||||
|
>>> merge_amplifier_restrictions(d1, d3)
|
||||||
|
{'params': {'restrictions': {'preamp_variety_list': [], 'booster_variety_list': []}}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
copy_dict1 = dict1.copy()
|
||||||
|
for key in dict2:
|
||||||
|
if key in dict1:
|
||||||
|
if isinstance(dict1[key], dict):
|
||||||
|
copy_dict1[key] = merge_amplifier_restrictions(copy_dict1[key], dict2[key])
|
||||||
|
else:
|
||||||
|
copy_dict1[key] = dict2[key]
|
||||||
|
return copy_dict1
|
||||||
|
|
||||||
|
def silent_remove(this_list, elem):
|
||||||
|
"""Remove matching elements from a list without raising ValueError
|
||||||
|
|
||||||
|
>>> li = [0, 1]
|
||||||
|
>>> li = silent_remove(li, 1)
|
||||||
|
>>> li
|
||||||
|
[0]
|
||||||
|
>>> li = silent_remove(li, 1)
|
||||||
|
>>> li
|
||||||
|
[0]
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
this_list.remove(elem)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return this_list
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ type’][‘subtype’]=object**
|
|||||||
Every equipment type is defined in JSON root with according name and
|
Every equipment type is defined in JSON root with according name and
|
||||||
array of parameters as value.
|
array of parameters as value.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: none
|
||||||
|
|
||||||
{"Edfa": [...],
|
{"Edfa": [...],
|
||||||
"Fiber": [...]
|
"Fiber": [...]
|
||||||
@@ -40,26 +40,33 @@ object contains **"type_variety":”type name”** name:value combination,
|
|||||||
if only one subtype exists **"type_variety"** name is not mandatory and
|
if only one subtype exists **"type_variety"** name is not mandatory and
|
||||||
it will be marked with **”default”** value.
|
it will be marked with **”default”** value.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json
|
||||||
|
|
||||||
{"Edfa": [{
|
{"Edfa": [{
|
||||||
"type_variety": "std_medium_gain",
|
"type_variety": "std_medium_gain",
|
||||||
|
"type_def": "variable_gain",
|
||||||
"gain_flatmax": 26,
|
"gain_flatmax": 26,
|
||||||
"gain_min": 15,
|
"gain_min": 15,
|
||||||
"p_max": 21,
|
"p_max": 23,
|
||||||
"nf_min": 6,
|
"nf_min": 6,
|
||||||
"nf_max": 10
|
"nf_max": 10,
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type_variety": "std_low_gain",
|
"type_variety": "std_low_gain",
|
||||||
|
"type_def": "variable_gain",
|
||||||
"gain_flatmax": 16,
|
"gain_flatmax": 16,
|
||||||
"gain_min": 8,
|
"gain_min": 8,
|
||||||
"p_max": 21,
|
"p_max": 23,
|
||||||
"nf_min": 7,
|
"nf_min": 6.5,
|
||||||
"nf_max": 11
|
"nf_max": 11,
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Fiber": [{
|
"Fiber": [{
|
||||||
|
"type_variety": "SSMF",
|
||||||
"dispersion": 1.67e-05,
|
"dispersion": 1.67e-05,
|
||||||
"gamma": 0.00127
|
"gamma": 0.00127
|
||||||
}
|
}
|
||||||
@@ -74,66 +81,167 @@ it will be marked with **”default”** value.
|
|||||||
1.2.1. EDFA element
|
1.2.1. EDFA element
|
||||||
*******************
|
*******************
|
||||||
|
|
||||||
Two types of EDFA definition are possible. Description JSON file
|
Four types of EDFA definition are possible. Description JSON file
|
||||||
location is in **transmission_main_example.py** folder:
|
location is in **transmission_main_example.py** folder:
|
||||||
|
|
||||||
- Advanced – with JSON file describing gain/noise figure tilt and
|
- Advanced – with JSON file describing gain/noise figure tilt and
|
||||||
gain/noise figure ripple. **"advanced_config_from_json"** value
|
gain/noise figure ripple. **"advanced_config_from_json"** value
|
||||||
contains filename.
|
contains filename.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json-object
|
||||||
|
|
||||||
"Edfa":[{
|
"Edfa":[{
|
||||||
|
"type_variety": "high_detail_model_example",
|
||||||
"gain_flatmax": 25,
|
"gain_flatmax": 25,
|
||||||
"gain_min": 15,
|
"gain_min": 15,
|
||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"advanced_config_from_json": "std_medium_gain_advanced_config.json"
|
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
- Default – with JSON file describing gain figure tilt and gain/noise
|
- Variable gain – with JSON file describing gain figure tilt and gain/noise
|
||||||
figure ripple. **”default_edfa_config.json”** as source file.
|
figure ripple. **”default_edfa_config.json”** as source file.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json-object
|
||||||
|
|
||||||
"Edfa":[{
|
"Edfa":[{
|
||||||
|
"type_variety": "std_medium_gain",
|
||||||
|
"type_def": "variable_gain",
|
||||||
"gain_flatmax": 26,
|
"gain_flatmax": 26,
|
||||||
"gain_min": 15,
|
"gain_min": 15,
|
||||||
"p_max": 21,
|
"p_max": 23,
|
||||||
"nf_min": 6,
|
"nf_min": 6,
|
||||||
"nf_max": 10
|
"nf_max": 10,
|
||||||
|
"out_voa_auto": false,
|
||||||
|
"allowed_for_design": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
- Fixed gain – with JSON file describing gain figure tilt and gain/noise
|
||||||
|
figure ripple. **”default_edfa_config.json”** as source file.
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
|
"Edfa":[{
|
||||||
|
"type_variety": "std_fixed_gain",
|
||||||
|
"type_def": "fixed_gain",
|
||||||
|
"gain_flatmax": 21,
|
||||||
|
"gain_min": 20,
|
||||||
|
"p_max": 21,
|
||||||
|
"nf0": 5.5,
|
||||||
|
"allowed_for_design": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
- openroadm – with JSON file describing gain figure tilt and gain/noise
|
||||||
|
figure ripple. **”default_edfa_config.json”** as source file.
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
|
"Edfa":[{
|
||||||
|
"type_variety": "low_noise",
|
||||||
|
"type_def": "openroadm",
|
||||||
|
"gain_flatmax": 27,
|
||||||
|
"gain_min": 12,
|
||||||
|
"p_max": 22,
|
||||||
|
"nf_coef": [-8.104e-4,-6.221e-2,-5.889e-1,37.62],
|
||||||
|
"allowed_for_design": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
1.2.2. Fiber element
|
1.2.2. Fiber element
|
||||||
********************
|
********************
|
||||||
|
|
||||||
Fiber element with its parameters:
|
Fiber element with its parameters:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json-object
|
||||||
|
|
||||||
"Fiber":[{
|
"Fiber":[{
|
||||||
|
"type_variety": "SSMF",
|
||||||
"dispersion": 1.67e-05,
|
"dispersion": 1.67e-05,
|
||||||
"gamma": 0.00127
|
"gamma": 0.00127
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
RamanFiber element
|
||||||
|
******************
|
||||||
|
|
||||||
|
A special variant of the regular ``Fiber`` where the simulation engine accounts for the Raman effect.
|
||||||
|
The newly added parameters are nested in the ``raman_efficiency`` dictionary.
|
||||||
|
Its shape corresponds to typical properties of silica.
|
||||||
|
More details are available from :cite:`curri_merit_2016`.
|
||||||
|
|
||||||
|
The ``cr`` property is the normailzed Raman efficiency, so it is is (almost) independent of the fiber type, while the coefficient actually giving Raman gain is g_R=C_R/Aeff.
|
||||||
|
|
||||||
|
The ``frequency_offset`` represents the spectral difference between the pumping photon and the one receiving energy.
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
|
"RamanFiber":[{
|
||||||
|
"type_variety": "SSMF",
|
||||||
|
"dispersion": 1.67e-05,
|
||||||
|
"gamma": 0.00127,
|
||||||
|
"raman_efficiency": {
|
||||||
|
"cr":[
|
||||||
|
0, 9.4E-06, 2.92E-05, 4.88E-05, 6.82E-05, 8.31E-05, 9.4E-05, 0.0001014, 0.0001069, 0.0001119,
|
||||||
|
0.0001217, 0.0001268, 0.0001365, 0.000149, 0.000165, 0.000181, 0.0001977, 0.0002192, 0.0002469,
|
||||||
|
0.0002749, 0.0002999, 0.0003206, 0.0003405, 0.0003592, 0.000374, 0.0003826, 0.0003841, 0.0003826,
|
||||||
|
0.0003802, 0.0003756, 0.0003549, 0.0003795, 0.000344, 0.0002933, 0.0002024, 0.0001158, 8.46E-05,
|
||||||
|
7.14E-05, 6.86E-05, 8.5E-05, 8.93E-05, 9.01E-05, 8.15E-05, 6.67E-05, 4.37E-05, 3.28E-05, 2.96E-05,
|
||||||
|
2.65E-05, 2.57E-05, 2.81E-05, 3.08E-05, 3.67E-05, 5.85E-05, 6.63E-05, 6.36E-05, 5.5E-05, 4.06E-05,
|
||||||
|
2.77E-05, 2.42E-05, 1.87E-05, 1.6E-05, 1.4E-05, 1.13E-05, 1.05E-05, 9.8E-06, 9.8E-06, 1.13E-05,
|
||||||
|
1.64E-05, 1.95E-05, 2.38E-05, 2.26E-05, 2.03E-05, 1.48E-05, 1.09E-05, 9.8E-06, 1.05E-05, 1.17E-05,
|
||||||
|
1.25E-05, 1.21E-05, 1.09E-05, 9.8E-06, 8.2E-06, 6.6E-06, 4.7E-06, 2.7E-06, 1.9E-06, 1.2E-06, 4E-07,
|
||||||
|
2E-07, 1E-07
|
||||||
|
],
|
||||||
|
"frequency_offset":[
|
||||||
|
0, 0.5e12, 1e12, 1.5e12, 2e12, 2.5e12, 3e12, 3.5e12, 4e12, 4.5e12, 5e12, 5.5e12, 6e12, 6.5e12, 7e12,
|
||||||
|
7.5e12, 8e12, 8.5e12, 9e12, 9.5e12, 10e12, 10.5e12, 11e12, 11.5e12, 12e12, 12.5e12, 12.75e12,
|
||||||
|
13e12, 13.25e12, 13.5e12, 14e12, 14.5e12, 14.75e12, 15e12, 15.5e12, 16e12, 16.5e12, 17e12,
|
||||||
|
17.5e12, 18e12, 18.25e12, 18.5e12, 18.75e12, 19e12, 19.5e12, 20e12, 20.5e12, 21e12, 21.5e12,
|
||||||
|
22e12, 22.5e12, 23e12, 23.5e12, 24e12, 24.5e12, 25e12, 25.5e12, 26e12, 26.5e12, 27e12, 27.5e12, 28e12,
|
||||||
|
28.5e12, 29e12, 29.5e12, 30e12, 30.5e12, 31e12, 31.5e12, 32e12, 32.5e12, 33e12, 33.5e12, 34e12, 34.5e12,
|
||||||
|
35e12, 35.5e12, 36e12, 36.5e12, 37e12, 37.5e12, 38e12, 38.5e12, 39e12, 39.5e12, 40e12, 40.5e12, 41e12,
|
||||||
|
41.5e12, 42e12
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
1.2.3 Roadm element
|
||||||
|
*******************
|
||||||
|
|
||||||
|
Roadm element with its parameters:
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
|
"Roadms":[{
|
||||||
|
"gain_mode_default_loss": 20,
|
||||||
|
"power_mode_pout_target": -20,
|
||||||
|
"add_drop_osnr": 38
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
1.2.3. Spans element
|
1.2.3. Spans element
|
||||||
********************
|
********************
|
||||||
|
|
||||||
Spans element with its parameters:
|
Spans element with its parameters:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json-object
|
||||||
|
|
||||||
"Spans":[{
|
"Spans":[{
|
||||||
|
"power_mode":true,
|
||||||
|
"delta_power_range_db": [0,0,0.5],
|
||||||
"max_length": 150,
|
"max_length": 150,
|
||||||
"length_units": "km",
|
"length_units": "km",
|
||||||
"max_loss": 28,
|
"max_loss": 28,
|
||||||
"padding": 10,
|
"padding": 10,
|
||||||
"EOL": 1,
|
"EOL": 0,
|
||||||
"con_loss": 0.5
|
"con_in": 0,
|
||||||
|
"con_out": 0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -143,15 +251,18 @@ Spans element with its parameters:
|
|||||||
|
|
||||||
Spectral information with its parameters:
|
Spectral information with its parameters:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json-object
|
||||||
|
|
||||||
"SI":[{
|
"SI":[{
|
||||||
"f_min": 191.3e12,
|
"f_min": 191.3e12,
|
||||||
"Nch": 80,
|
|
||||||
"baud_rate": 32e9,
|
"baud_rate": 32e9,
|
||||||
"spacing": 75e9,
|
"f_max":195.1e12,
|
||||||
|
"spacing": 50e9,
|
||||||
|
"power_dbm": 0,
|
||||||
|
"power_range_db": [0,0,0.5],
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"power": 1.2589e-3
|
"tx_osnr": 40,
|
||||||
|
"sys_margins": 0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -162,7 +273,9 @@ Spectral information with its parameters:
|
|||||||
Transceiver element with its parameters. **”mode”** can contain multiple
|
Transceiver element with its parameters. **”mode”** can contain multiple
|
||||||
Transceiver operation formats.
|
Transceiver operation formats.
|
||||||
|
|
||||||
.. code-block::
|
Note that ``OSNR`` parameter refers to the receiver's minimal OSNR threshold for a given mode.
|
||||||
|
|
||||||
|
.. code-block:: json-object
|
||||||
|
|
||||||
"Transceiver":[{
|
"Transceiver":[{
|
||||||
"frequency":{
|
"frequency":{
|
||||||
@@ -171,16 +284,24 @@ Transceiver operation formats.
|
|||||||
},
|
},
|
||||||
"mode":[
|
"mode":[
|
||||||
{
|
{
|
||||||
"format": "PS_SP64_1",
|
"format": "mode 1",
|
||||||
"baudrate": 32e9,
|
"baud_rate": 32e9,
|
||||||
"OSNR": 9,
|
"OSNR": 11,
|
||||||
"bit_rate": 100e9
|
"bit_rate": 100e9,
|
||||||
|
"roll_off": 0.15,
|
||||||
|
"tx_osnr": 40,
|
||||||
|
"min_spacing": 37.5e9,
|
||||||
|
"cost":1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"format": "PS_SP64_2",
|
"format": "mode 2",
|
||||||
"baudrate": 66e9,
|
"baud_rate": 66e9,
|
||||||
"OSNR": 10,
|
"OSNR": 15,
|
||||||
"bit_rate": 200e9
|
"bit_rate": 200e9,
|
||||||
|
"roll_off": 0.15,
|
||||||
|
"tx_osnr": 40,
|
||||||
|
"min_spacing": 75e9,
|
||||||
|
"cost":1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -215,7 +336,7 @@ Network description JSON file root consist of three unordered parts:
|
|||||||
|
|
||||||
- connections – contains array of unidirectional connection objects
|
- connections – contains array of unidirectional connection objects
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: none
|
||||||
|
|
||||||
{"network_name": "Example Network",
|
{"network_name": "Example Network",
|
||||||
"elements": [{...},
|
"elements": [{...},
|
||||||
@@ -244,10 +365,10 @@ obligatory.
|
|||||||
|
|
||||||
Transceiver element with its parameters.
|
Transceiver element with its parameters.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json
|
||||||
|
|
||||||
{"uid": "trx Site_A",
|
{"uid": "trx Site_A",
|
||||||
“metadata": {
|
"metadata": {
|
||||||
"location": {
|
"location": {
|
||||||
"city": "Site_A",
|
"city": "Site_A",
|
||||||
"region": "",
|
"region": "",
|
||||||
@@ -266,7 +387,7 @@ Transceiver element with its parameters.
|
|||||||
ROADM element with its parameters. **“params”** is optional, if not used
|
ROADM element with its parameters. **“params”** is optional, if not used
|
||||||
default loss value of 20dB is used.
|
default loss value of 20dB is used.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json
|
||||||
|
|
||||||
{"uid": "roadm Site_A",
|
{"uid": "roadm Site_A",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
@@ -290,12 +411,12 @@ default loss value of 20dB is used.
|
|||||||
Fused element with its parameters. **“params”** is optional, if not used
|
Fused element with its parameters. **“params”** is optional, if not used
|
||||||
default loss value of 1dB is used.
|
default loss value of 1dB is used.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json
|
||||||
|
|
||||||
{"uid": "ingress fused spans in Site_B",
|
{"uid": "ingress fused spans in Site_B",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"location": {
|
"location": {
|
||||||
“city": "Site_B",
|
"city": "Site_B",
|
||||||
"region": "",
|
"region": "",
|
||||||
"latitude": 0,
|
"latitude": 0,
|
||||||
"longitude": 0
|
"longitude": 0
|
||||||
@@ -313,7 +434,7 @@ default loss value of 1dB is used.
|
|||||||
|
|
||||||
Fiber element with its parameters.
|
Fiber element with its parameters.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json
|
||||||
|
|
||||||
{"uid": "fiber (Site_A \\u2192 Site_B)",
|
{"uid": "fiber (Site_A \\u2192 Site_B)",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
@@ -333,13 +454,56 @@ Fiber element with its parameters.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2.2.5. RamanFiber element
|
||||||
|
*************************
|
||||||
|
|
||||||
2.2.5. EDFA element
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"uid": "Span1",
|
||||||
|
"type": "RamanFiber",
|
||||||
|
"type_variety": "SSMF",
|
||||||
|
"operational": {
|
||||||
|
"temperature": 283,
|
||||||
|
"raman_pumps": [
|
||||||
|
{
|
||||||
|
"power": 200e-3,
|
||||||
|
"frequency": 205e12,
|
||||||
|
"propagation_direction": "counterprop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"power": 206e-3,
|
||||||
|
"frequency": 201e12,
|
||||||
|
"propagation_direction": "counterprop"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
2.2.6. EDFA element
|
||||||
********************
|
********************
|
||||||
|
|
||||||
EDFA element with its parameters.
|
EDFA element with its parameters.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json
|
||||||
|
|
||||||
{"uid": "Edfa1",
|
{"uid": "Edfa1",
|
||||||
"type": "Edfa",
|
"type": "Edfa",
|
||||||
@@ -365,8 +529,31 @@ Each unidirectional connection object in connections array consist of
|
|||||||
two unordered **”from_node”** and **”to_node”** name pair with values
|
two unordered **”from_node”** and **”to_node”** name pair with values
|
||||||
corresponding to element **”uid”**
|
corresponding to element **”uid”**
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: json
|
||||||
|
|
||||||
{"from_node": "roadm Site_C",
|
{"from_node": "roadm Site_C",
|
||||||
"to_node": "trx Site_C"
|
"to_node": "trx Site_C"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
************************
|
||||||
|
3. Simulation Parameters
|
||||||
|
************************
|
||||||
|
|
||||||
|
Additional details of the simulation are controlled via ``sim_params.json``:
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"raman_computed_channels": [1, 18, 37, 56, 75],
|
||||||
|
"raman_parameters": {
|
||||||
|
"flag_raman": true,
|
||||||
|
"space_resolution": 10e3,
|
||||||
|
"tolerance": 1e-8
|
||||||
|
},
|
||||||
|
"nli_parameters": {
|
||||||
|
"nli_method_name": "ggn_spectrally_separated",
|
||||||
|
"wdm_grid_size": 50e9,
|
||||||
|
"dispersion_tolerance": 1,
|
||||||
|
"phase_shift_tollerance": 0.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,40 +1,62 @@
|
|||||||
{
|
{
|
||||||
"paths": [
|
"response": [
|
||||||
{
|
{
|
||||||
"path": {
|
"response-id": null,
|
||||||
"path-id": null,
|
|
||||||
"path-properties": {
|
"path-properties": {
|
||||||
"path-metric": [
|
"path-metric": [
|
||||||
{
|
{
|
||||||
"metric-type": null,
|
"metric-type": "SNR@bandwidth",
|
||||||
|
"accumulative-value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metric-type": "SNR@0.1nm",
|
||||||
|
"accumulative-value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metric-type": "OSNR@bandwidth",
|
||||||
|
"accumulative-value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metric-type": "OSNR@0.1nm",
|
||||||
|
"accumulative-value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metric-type": "reference_power",
|
||||||
|
"accumulative-value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metric-type": "path_bandwidth",
|
||||||
"accumulative-value": null
|
"accumulative-value": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"path-srlgs": {
|
|
||||||
"usage": "not used yet",
|
|
||||||
"values": ["not used yet"]
|
|
||||||
},
|
|
||||||
"path-route-objects": [
|
"path-route-objects": [
|
||||||
{
|
{
|
||||||
"path-route-object": {
|
"path-route-object": {
|
||||||
"index": null,
|
"index": 0,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": null,
|
"node-id": null,
|
||||||
"link-tp-id": null,
|
"link-tp-id": null
|
||||||
"hop-type": null,
|
}
|
||||||
"direction": "not used"
|
}
|
||||||
},
|
},
|
||||||
"label-hop": {
|
{
|
||||||
"te-label": {
|
"path-route-object": {
|
||||||
"generic": "not used yet",
|
"index": 1,
|
||||||
"direction": "not used yet"
|
"transponder": {
|
||||||
|
"transponder-type": null,
|
||||||
|
"transponder-mode": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
{
|
||||||
]
|
"path-route-object": {
|
||||||
|
"index": 2,
|
||||||
|
"num-unnum-hop": {
|
||||||
|
"node-id": null,
|
||||||
|
"link-tp-id": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
[pytest]
|
[pytest]
|
||||||
addopts = -p no:warnings
|
addopts = --doctest-modules
|
||||||
|
|||||||
@@ -1,40 +1,14 @@
|
|||||||
alabaster==0.7.12
|
alabaster>=0.7.12,<1
|
||||||
atomicwrites==1.2.1
|
docutils==0.15.2
|
||||||
attrs==18.2.0
|
flask==1.0.2
|
||||||
Babel==2.6.0
|
flask-restful==0.3.7
|
||||||
certifi==2018.10.15
|
matplotlib>=3.1.0,<4
|
||||||
chardet==3.0.4
|
networkx>=2.3,<3
|
||||||
cycler==0.10.0
|
numpy>=1.16.1,<2
|
||||||
decorator==4.3.0
|
pandas==0.24.2
|
||||||
docutils==0.14
|
Pygments>=2.4.2,<3
|
||||||
idna==2.7
|
pytest>=4.0.0,<5
|
||||||
imagesize==1.1.0
|
scipy>=1.3.0,<2
|
||||||
Jinja2==2.10
|
Sphinx>=2.1.1,<3
|
||||||
kiwisolver==1.0.1
|
sphinxcontrib-bibtex>=0.4.2,<1
|
||||||
latexcodec==1.0.5
|
xlrd>=1.2.0,<2
|
||||||
MarkupSafe==1.0
|
|
||||||
matplotlib==3.0.0
|
|
||||||
more-itertools==4.3.0
|
|
||||||
networkx==2.2
|
|
||||||
numpy==1.15.2
|
|
||||||
oset==0.1.3
|
|
||||||
packaging==18.0
|
|
||||||
pluggy==0.7.1
|
|
||||||
py==1.7.0
|
|
||||||
pybtex==0.21
|
|
||||||
pybtex-docutils==0.2.1
|
|
||||||
Pygments==2.2.0
|
|
||||||
pyparsing==2.2.2
|
|
||||||
pytest==3.8.2
|
|
||||||
python-dateutil==2.7.3
|
|
||||||
pytz==2018.5
|
|
||||||
PyYAML==3.13
|
|
||||||
requests==2.19.1
|
|
||||||
scipy==1.1.0
|
|
||||||
six==1.11.0
|
|
||||||
snowballstemmer==1.2.1
|
|
||||||
Sphinx==1.8.1
|
|
||||||
sphinxcontrib-bibtex==0.4.0
|
|
||||||
sphinxcontrib-websupport==1.1.0
|
|
||||||
urllib3==1.23
|
|
||||||
xlrd==1.1.0
|
|
||||||
|
|||||||
@@ -6,54 +6,71 @@
|
|||||||
"destination": null,
|
"destination": null,
|
||||||
"src-tp-id": null,
|
"src-tp-id": null,
|
||||||
"dst-tp-id": null,
|
"dst-tp-id": null,
|
||||||
|
"explicit-route-objects": {
|
||||||
|
"route-object-include-exclude": [
|
||||||
|
{
|
||||||
|
"explicit-route-usage": null,
|
||||||
|
"index": null,
|
||||||
|
"num-unnum-hop": {
|
||||||
|
"node-id": null,
|
||||||
|
"link-tp-id": null,
|
||||||
|
"hop-type": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"explicit-route-usage": null,
|
||||||
|
"index": null,
|
||||||
|
"label-hop": {
|
||||||
|
"N": null,
|
||||||
|
"M": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"explicit-route-usage": null,
|
||||||
|
"index": null,
|
||||||
|
"transponder": {
|
||||||
|
"transponder-type": null,
|
||||||
|
"transponder-mode": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"explicit-route-usage": null,
|
||||||
|
"index": null,
|
||||||
|
"regenerator": {
|
||||||
|
"regenerator-id": null,
|
||||||
|
"transponder-type": null,
|
||||||
|
"transponder-mode": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
"trx_type": null,
|
"trx_type": "name of the tsp type_variety as listed in the library",
|
||||||
"trx_mode": null,
|
"trx_mode": "optional, name of the mode as listed in the tsp type_variety",
|
||||||
"effective-freq-slot": [
|
"effective-freq-slot": [
|
||||||
{
|
{
|
||||||
"n": "null",
|
"n": "null",
|
||||||
"m": "null"
|
"m": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": null,
|
"spacing": mandatory decimal Hz,
|
||||||
"max-nb-of-channel": null,
|
"max-nb-of-channel": optional integer,
|
||||||
"output-power": null,
|
"output-power": optional decimal W,
|
||||||
"path_bandwidth": null
|
"path_bandwidth": optional bit/s
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"optimizations": {
|
}
|
||||||
"explicit-route-include-objects": {
|
],
|
||||||
"route-object-include-object": [
|
"synchronization": [ list of disjunctions, optional
|
||||||
{
|
{
|
||||||
"index": null,
|
"synchronization-id": "3",
|
||||||
"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": {
|
"svec": {
|
||||||
"relaxable": "True",
|
"relaxable": "True",
|
||||||
"link-diverse": "False",
|
"disjointness": "node link",
|
||||||
"node-diverse": "False",
|
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
null ]
|
null, null ]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
4
setup.py
4
setup.py
@@ -11,13 +11,13 @@ with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='gnpy',
|
name='gnpy',
|
||||||
version='0.1.3',
|
version='2.1',
|
||||||
description='route planning and optimization tool for mesh optical networks',
|
description='route planning and optimization tool for mesh optical networks',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type='text/x-rst; charset=UTF-8',
|
long_description_content_type='text/x-rst; charset=UTF-8',
|
||||||
url='https://github.com/Telecominfraproject/gnpy',
|
url='https://github.com/Telecominfraproject/gnpy',
|
||||||
author='Telecom Infra Project',
|
author='Telecom Infra Project',
|
||||||
author_email='james.powell@telecominfraproject.com',
|
author_email='jan.kundrat@telecominfraproject.com',
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 3 - Alpha',
|
'Development Status :: 3 - Alpha',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
|
|||||||
@@ -205,6 +205,36 @@
|
|||||||
"longitude": 0
|
"longitude": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "Att_B",
|
||||||
|
"type": "Fused",
|
||||||
|
"params":{
|
||||||
|
"loss":16
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 1.0,
|
||||||
|
"city": "Corlay",
|
||||||
|
"region": "RLD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "Att_F",
|
||||||
|
"type": "Fused",
|
||||||
|
"params":{
|
||||||
|
"loss":16
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 1.0,
|
||||||
|
"city": "Corlay",
|
||||||
|
"region": "RLD"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
@@ -247,6 +277,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "Edfa5",
|
"from_node": "Edfa5",
|
||||||
|
"to_node": "Att_F"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "Att_F",
|
||||||
"to_node": "trx F"
|
"to_node": "trx F"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -255,6 +289,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "Edfa1",
|
"from_node": "Edfa1",
|
||||||
|
"to_node": "Att_B"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "Att_B",
|
||||||
"to_node": "trx B"
|
"to_node": "trx B"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ def compare_networks(expected, actual):
|
|||||||
def compare_services(expected, actual):
|
def compare_services(expected, actual):
|
||||||
requests = compare(expected['path-request'], actual['path-request'],
|
requests = compare(expected['path-request'], actual['path-request'],
|
||||||
key=lambda el: el['request-id'])
|
key=lambda el: el['request-id'])
|
||||||
|
synchronizations = compare(expected['path-request'], expected['path-request'],
|
||||||
|
key=lambda el: el['request-id'])
|
||||||
|
if 'synchronization' in expected.keys():
|
||||||
synchronizations = compare(expected['synchronization'], actual['synchronization'],
|
synchronizations = compare(expected['synchronization'], actual['synchronization'],
|
||||||
key=lambda el: el['synchronization-id'])
|
key=lambda el: el['synchronization-id'])
|
||||||
return ServicesResults(requests, synchronizations)
|
return ServicesResults(requests, synchronizations)
|
||||||
|
|||||||
196470
tests/data/CORONET_Global_Topology_auto_design_expected.json
Normal file
196470
tests/data/CORONET_Global_Topology_auto_design_expected.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,11 @@
|
|||||||
{ "Edfa":[{
|
{ "Edfa":[{
|
||||||
"type_variety": "CienaDB_medium_gain",
|
"type_variety": "CienaDB_medium_gain",
|
||||||
|
"type_def": "advanced_model",
|
||||||
"gain_flatmax": 25,
|
"gain_flatmax": 25,
|
||||||
"gain_min": 15,
|
"gain_min": 15,
|
||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||||
|
"out_voa_auto": false,
|
||||||
"allowed_for_design": true
|
"allowed_for_design": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -14,6 +16,7 @@
|
|||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"nf_min": 6,
|
"nf_min": 6,
|
||||||
"nf_max": 10,
|
"nf_max": 10,
|
||||||
|
"out_voa_auto": false,
|
||||||
"allowed_for_design": true
|
"allowed_for_design": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -24,6 +27,7 @@
|
|||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"nf_min": 7,
|
"nf_min": 7,
|
||||||
"nf_max": 11,
|
"nf_max": 11,
|
||||||
|
"out_voa_auto": false,
|
||||||
"allowed_for_design": true
|
"allowed_for_design": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -34,6 +38,7 @@
|
|||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"nf_min": 5.8,
|
"nf_min": 5.8,
|
||||||
"nf_max": 10,
|
"nf_max": 10,
|
||||||
|
"out_voa_auto": false,
|
||||||
"allowed_for_design": true
|
"allowed_for_design": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -44,6 +49,15 @@
|
|||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"nf0": 5,
|
"nf0": 5,
|
||||||
"allowed_for_design": true
|
"allowed_for_design": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type_variety": "std_booster",
|
||||||
|
"type_def": "fixed_gain",
|
||||||
|
"gain_flatmax": 21,
|
||||||
|
"gain_min": 20,
|
||||||
|
"p_max": 21,
|
||||||
|
"nf0": 5,
|
||||||
|
"allowed_for_design": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Fiber":[{
|
"Fiber":[{
|
||||||
@@ -52,9 +66,11 @@
|
|||||||
"gamma": 0.00127
|
"gamma": 0.00127
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Spans":[{
|
"Span":[{
|
||||||
"power_mode":true,
|
"power_mode":true,
|
||||||
"delta_power_range_db": [0,0,1],
|
"delta_power_range_db": [0,0,0.5],
|
||||||
|
"max_fiber_lineic_loss_for_raman": 0.25,
|
||||||
|
"target_extended_gain": 2.5,
|
||||||
"max_length": 150,
|
"max_length": 150,
|
||||||
"length_units": "km",
|
"length_units": "km",
|
||||||
"max_loss": 28,
|
"max_loss": 28,
|
||||||
@@ -64,10 +80,13 @@
|
|||||||
"con_out": 0
|
"con_out": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Roadms":[{
|
"Roadm":[{
|
||||||
"gain_mode_default_loss": 20,
|
"target_pch_out_db": -20,
|
||||||
"power_mode_pout_target": -20,
|
"add_drop_osnr": 38,
|
||||||
"add_drop_osnr": 100
|
"restrictions": {
|
||||||
|
"preamp_variety_list":[],
|
||||||
|
"booster_variety_list":[]
|
||||||
|
}
|
||||||
}],
|
}],
|
||||||
"SI":[{
|
"SI":[{
|
||||||
"f_min": 191.3e12,
|
"f_min": 191.3e12,
|
||||||
@@ -75,7 +94,7 @@
|
|||||||
"baud_rate": 32e9,
|
"baud_rate": 32e9,
|
||||||
"spacing": 50e9,
|
"spacing": 50e9,
|
||||||
"power_dbm": 0,
|
"power_dbm": 0,
|
||||||
"power_range_db": [0,0.5,0.5],
|
"power_range_db": [0,0,0.5],
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 100,
|
"tx_osnr": 100,
|
||||||
"sys_margins": 0
|
"sys_margins": 0
|
||||||
|
|||||||
Binary file not shown.
@@ -1,698 +0,0 @@
|
|||||||
{
|
|
||||||
"elements": [
|
|
||||||
{
|
|
||||||
"uid": "trx Lannion_CAS",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Lannion_CAS",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx Lorient_KMA",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Lorient_KMA",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx Vannes_KBE",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Vannes_KBE",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx Rennes_STA",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Rennes_STA",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx Brest_KLA",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Brest_KLA",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm Lannion_CAS",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Lannion_CAS",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm Lorient_KMA",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Lorient_KMA",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm Vannes_KBE",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Vannes_KBE",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm Rennes_STA",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Rennes_STA",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm Brest_KLA",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Brest_KLA",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "west fused spans in Corlay",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Corlay",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "west fused spans in Loudeac",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Loudeac",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east fused spans in Corlay",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Corlay",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east fused spans in Loudeac",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Loudeac",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → Corlay)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 20.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Corlay → Loudeac)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 50.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Loudeac → Lorient_KMA)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 60.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lorient_KMA → Vannes_KBE)-F01",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 10.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → Stbrieuc)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 60.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Stbrieuc → Rennes_STA)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 65.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → Morlaix)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 40.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Morlaix → Brest_KLA)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 35.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Corlay → Lannion_CAS)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 20.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Loudeac → Corlay)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 50.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lorient_KMA → Loudeac)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 60.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Vannes_KBE → Lorient_KMA)-F01",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 10.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Stbrieuc → Lannion_CAS)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 60.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Rennes_STA → Stbrieuc)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 65.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Morlaix → Lannion_CAS)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 40.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Brest_KLA → Morlaix)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 35.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east edfa in Lannion_CAS to Morlaix",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Lannion_CAS",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Edfa",
|
|
||||||
"type_variety": "test",
|
|
||||||
"operational": {
|
|
||||||
"gain_target": 0,
|
|
||||||
"tilt_target": 0,
|
|
||||||
"out_voa": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east edfa in Lannion_CAS to Corlay",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Lannion_CAS",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Edfa",
|
|
||||||
"type_variety": "test",
|
|
||||||
"operational": {
|
|
||||||
"gain_target": 0,
|
|
||||||
"tilt_target": 0,
|
|
||||||
"out_voa": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east edfa in Lannion_CAS to Stbrieuc",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Lannion_CAS",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Edfa",
|
|
||||||
"type_variety": "test",
|
|
||||||
"operational": {
|
|
||||||
"gain_target": 0,
|
|
||||||
"tilt_target": 0,
|
|
||||||
"out_voa": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east edfa in Corlay to Loudeac",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Corlay",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Edfa",
|
|
||||||
"type_variety": "test",
|
|
||||||
"operational": {
|
|
||||||
"gain_target": 0,
|
|
||||||
"tilt_target": 0,
|
|
||||||
"out_voa": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"connections": [
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "east edfa in Lannion_CAS to Corlay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east edfa in Lannion_CAS to Corlay",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Corlay)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Corlay → Lannion_CAS)-",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "east edfa in Lannion_CAS to Stbrieuc"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east edfa in Lannion_CAS to Stbrieuc",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Stbrieuc)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Stbrieuc → Lannion_CAS)-",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "east edfa in Lannion_CAS to Morlaix"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east edfa in Lannion_CAS to Morlaix",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Morlaix)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Morlaix → Lannion_CAS)-",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Corlay)-",
|
|
||||||
"to_node": "west fused spans in Corlay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "west fused spans in Corlay",
|
|
||||||
"to_node": "fiber (Corlay → Loudeac)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Loudeac → Corlay)-",
|
|
||||||
"to_node": "east fused spans in Corlay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east fused spans in Corlay",
|
|
||||||
"to_node": "fiber (Corlay → Lannion_CAS)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Corlay → Loudeac)-",
|
|
||||||
"to_node": "west fused spans in Loudeac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "west fused spans in Loudeac",
|
|
||||||
"to_node": "fiber (Loudeac → Lorient_KMA)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lorient_KMA → Loudeac)-",
|
|
||||||
"to_node": "east fused spans in Loudeac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east fused spans in Loudeac",
|
|
||||||
"to_node": "fiber (Loudeac → Corlay)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lorient_KMA",
|
|
||||||
"to_node": "fiber (Lorient_KMA → Loudeac)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Loudeac → Lorient_KMA)-",
|
|
||||||
"to_node": "roadm Lorient_KMA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lorient_KMA",
|
|
||||||
"to_node": "fiber (Lorient_KMA → Vannes_KBE)-F01"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Vannes_KBE → Lorient_KMA)-F01",
|
|
||||||
"to_node": "roadm Lorient_KMA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Vannes_KBE",
|
|
||||||
"to_node": "fiber (Vannes_KBE → Lorient_KMA)-F01"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lorient_KMA → Vannes_KBE)-F01",
|
|
||||||
"to_node": "roadm Vannes_KBE"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Stbrieuc)-",
|
|
||||||
"to_node": "fiber (Stbrieuc → Rennes_STA)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Rennes_STA → Stbrieuc)-",
|
|
||||||
"to_node": "fiber (Stbrieuc → Lannion_CAS)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Rennes_STA",
|
|
||||||
"to_node": "fiber (Rennes_STA → Stbrieuc)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Stbrieuc → Rennes_STA)-",
|
|
||||||
"to_node": "roadm Rennes_STA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Morlaix)-",
|
|
||||||
"to_node": "fiber (Morlaix → Brest_KLA)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Brest_KLA → Morlaix)-",
|
|
||||||
"to_node": "fiber (Morlaix → Lannion_CAS)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Brest_KLA",
|
|
||||||
"to_node": "fiber (Brest_KLA → Morlaix)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Morlaix → Brest_KLA)-",
|
|
||||||
"to_node": "roadm Brest_KLA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
{
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"synchronization": [
|
|
||||||
{
|
|
||||||
"synchronization-id": "0",
|
|
||||||
"svec": {
|
|
||||||
"relaxable": "False",
|
|
||||||
"link-diverse": "True",
|
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
|
||||||
"0",
|
|
||||||
"1"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"synchronization-id": "1",
|
|
||||||
"svec": {
|
|
||||||
"relaxable": "False",
|
|
||||||
"link-diverse": "True",
|
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
97
tests/data/expected_results_science_utils.csv
Normal file
97
tests/data/expected_results_science_utils.csv
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
,signal,ase,nli
|
||||||
|
0,0.0002869472910750076,3.829243751386179e-08,2.157043502374111e-07
|
||||||
|
1,0.000284426444181902,3.8108068606265256e-08,2.1799950841472648e-07
|
||||||
|
2,0.0002819286625240274,3.7925434667811625e-08,2.2023841125044652e-07
|
||||||
|
3,0.0002794537215642205,3.774451238936698e-08,2.224218994135113e-07
|
||||||
|
4,0.0002756243295734432,3.739256063612741e-08,2.2343448272114653e-07
|
||||||
|
5,0.0002718482755003954,3.7044477620123535e-08,2.2437826192962217e-07
|
||||||
|
6,0.0002681247979313455,3.6700201831013766e-08,2.2525495466695055e-07
|
||||||
|
7,0.0002644507001383656,3.635953568122817e-08,2.2606415187870565e-07
|
||||||
|
8,0.0002608253488031495,3.602242321653821e-08,2.268074852150968e-07
|
||||||
|
9,0.00025690468888571607,3.564391587795796e-08,2.2718285844824803e-07
|
||||||
|
10,0.0002530414048173237,3.5269661038482016e-08,2.2749429758476786e-07
|
||||||
|
11,0.0002492279873568786,3.4899736994459975e-08,2.277374766526846e-07
|
||||||
|
12,0.0002454639458992114,3.4534068616323406e-08,2.2791414400784552e-07
|
||||||
|
13,0.00024174879168999762,3.417258192135115e-08,2.280260208417629e-07
|
||||||
|
14,0.00023798746912556782,3.3802278288721e-08,2.2798420759779948e-07
|
||||||
|
15,0.00023427697848575827,3.3436265380528345e-08,2.2788101592690985e-07
|
||||||
|
16,0.00023061678363205047,3.30744682841412e-08,2.2771816297652923e-07
|
||||||
|
17,0.00022700656967542085,3.271682680678683e-08,2.2749755602884014e-07
|
||||||
|
18,0.0002234457948096593,3.236326805537296e-08,2.236182244259085e-07
|
||||||
|
19,0.0002195336193536736,3.195819496314336e-08,2.193976173454328e-07
|
||||||
|
20,0.00021568313139087874,3.155821230359698e-08,2.1524945887103656e-07
|
||||||
|
21,0.00021189361260563733,3.116322489050993e-08,2.1117277567390236e-07
|
||||||
|
22,0.00020816423698459606,3.0773141693336075e-08,2.0716649124094935e-07
|
||||||
|
23,0.0002044941867087381,3.038787321635763e-08,2.032295417993187e-07
|
||||||
|
24,0.00020116081520673765,3.00440338127331e-08,1.9963693210324778e-07
|
||||||
|
25,0.00019787569461895006,2.9704199888387147e-08,1.9610141536963145e-07
|
||||||
|
26,0.00019463824873065924,2.9368302916351224e-08,1.9262221997372471e-07
|
||||||
|
27,0.0001914486066928752,2.903632427420397e-08,1.8919927457565086e-07
|
||||||
|
28,0.00018830616497930887,2.870819640079397e-08,1.858317840670677e-07
|
||||||
|
29,0.00018521032563368435,2.838385281897912e-08,1.8251896218718178e-07
|
||||||
|
30,0.00018216049720979434,2.8063228018898468e-08,1.7926003240909075e-07
|
||||||
|
31,0.0001791561867005718,2.7746255438682553e-08,1.76054318231933e-07
|
||||||
|
32,0.00017619680881744213,2.7432871709278503e-08,1.7290105534292413e-07
|
||||||
|
33,0.00017328178390236163,2.7123014438128492e-08,1.6979948820364567e-07
|
||||||
|
34,0.00017049664136784971,2.6828118382010868e-08,1.668331233176527e-07
|
||||||
|
35,0.0001677518922618999,2.6536524600591003e-08,1.639139770351797e-07
|
||||||
|
36,0.00016504703499520338,2.6248178236430935e-08,1.6104139135571758e-07
|
||||||
|
37,0.0001623826677977635,2.596311344676757e-08,1.579538179464147e-07
|
||||||
|
38,0.0001597582427278653,2.5681275450827438e-08,1.549209871570718e-07
|
||||||
|
39,0.0001571732182028194,2.5402610321183817e-08,1.5194201541886346e-07
|
||||||
|
40,0.00015462705891566638,2.512706495768609e-08,1.490160317195833e-07
|
||||||
|
41,0.00015212101646392648,2.4854546722771583e-08,1.4614388817377845e-07
|
||||||
|
42,0.00014965447757986727,2.4585006051161647e-08,1.4332463586636234e-07
|
||||||
|
43,0.00014722683809507942,2.4318394065447274e-08,1.4055734193947907e-07
|
||||||
|
44,0.0001447164668892396,2.4034548127308286e-08,1.3772590008270512e-07
|
||||||
|
45,0.00014224784112375704,2.3753926686114635e-08,1.3494914625939818e-07
|
||||||
|
46,0.00013982028367499942,2.3476475779461364e-08,1.3222606385780792e-07
|
||||||
|
47,0.00013743418748445304,2.3202244204140228e-08,1.2955665313419502e-07
|
||||||
|
48,0.00013508884015386575,2.2931178307200807e-08,1.269398709602497e-07
|
||||||
|
49,0.00013278354172499636,2.2663225269637508e-08,1.243746944213211e-07
|
||||||
|
50,0.0001305176041972383,2.2398333101097452e-08,1.2186012017916144e-07
|
||||||
|
51,0.00012829168984639723,2.2136419884279648e-08,1.1939640981690787e-07
|
||||||
|
52,0.00012610506317956035,2.1877436733290284e-08,1.169825203056231e-07
|
||||||
|
53,0.000123957002859191,2.1621335420785434e-08,1.1461743054419468e-07
|
||||||
|
54,0.00012180241033649304,2.1360152817604167e-08,1.1225922783038433e-07
|
||||||
|
55,0.00011968650905779935,2.1101906890578305e-08,1.0994951537259513e-07
|
||||||
|
56,0.000117608577762061,2.0846548870078847e-08,1.0757395097864581e-07
|
||||||
|
57,0.00011556891128259058,2.0594151467353748e-08,1.0524972555992308e-07
|
||||||
|
58,0.00011356676177301841,2.0344667169015006e-08,1.0297570549831857e-07
|
||||||
|
59,0.00011160139690545192,2.00980493433389e-08,1.0075078305548045e-07
|
||||||
|
60,0.00010967209909252646,1.985425227516509e-08,9.857387536569511e-08
|
||||||
|
61,0.00010777915187087522,1.9613208260272527e-08,9.644480679616336e-08
|
||||||
|
62,0.00010592181397175155,1.937487453011716e-08,9.436248424611683e-08
|
||||||
|
63,0.00010409936038610526,1.913920913597429e-08,9.23258408012148e-08
|
||||||
|
64,0.00010246447558375888,1.8936226281729442e-08,9.046927135291653e-08
|
||||||
|
65,0.00010085803630104006,1.87354387522902e-08,8.865067925960373e-08
|
||||||
|
66,9.927950010553608e-05,1.853681852284204e-08,8.686925127146881e-08
|
||||||
|
67,9.772837346090978e-05,1.834034443508121e-08,8.512422533827548e-08
|
||||||
|
68,9.620413430112097e-05,1.8145990199784238e-08,8.341482250639003e-08
|
||||||
|
69,9.470627135913274e-05,1.795373041706864e-08,8.174028142913882e-08
|
||||||
|
70,9.323428359797426e-05,1.776354066998682e-08,8.009985766376296e-08
|
||||||
|
71,9.178813743816942e-05,1.7575386852678668e-08,7.849321446941785e-08
|
||||||
|
72,9.03673300948529e-05,1.7389247191220127e-08,7.691961625609547e-08
|
||||||
|
73,8.897136946427622e-05,1.7205101122769978e-08,7.537834446342857e-08
|
||||||
|
74,8.760740745800998e-05,1.7025337039390582e-08,7.387513417420477e-08
|
||||||
|
75,8.626710469266086e-05,1.684760610568072e-08,7.274492099363918e-08
|
||||||
|
76,8.495000573672162e-05,1.6671894857242002e-08,7.163427447510873e-08
|
||||||
|
77,8.365569697520994e-05,1.649819993412593e-08,7.054284583689279e-08
|
||||||
|
78,8.238374036674246e-05,1.6326513144182658e-08,6.947026569965565e-08
|
||||||
|
79,8.113370706498376e-05,1.6156829499842502e-08,6.841617243780552e-08
|
||||||
|
80,7.990517700269747e-05,1.5989147949913657e-08,6.738021182874466e-08
|
||||||
|
81,7.86978423091888e-05,1.5823469853370494e-08,6.636212425984957e-08
|
||||||
|
82,7.751129541079691e-05,1.5659805288834794e-08,6.536156604375694e-08
|
||||||
|
83,7.634513730458643e-05,1.549817228640182e-08,6.4378200720386e-08
|
||||||
|
84,7.530262080974352e-05,1.5364274253504764e-08,6.349909645089537e-08
|
||||||
|
85,7.427675504203847e-05,1.523236211656126e-08,6.263403294276386e-08
|
||||||
|
86,7.326723873728748e-05,1.5102509684796054e-08,6.17827561543225e-08
|
||||||
|
87,7.227232864621635e-05,1.497407531211962e-08,6.094379608688325e-08
|
||||||
|
88,7.129179755315639e-05,1.4847053209180731e-08,6.011696114034632e-08
|
||||||
|
89,7.032542203609286e-05,1.4721438007057792e-08,5.930206291361871e-08
|
||||||
|
90,6.937298231674387e-05,1.4597224779058979e-08,5.8498916078193026e-08
|
||||||
|
91,6.843339696762452e-05,1.4474430063551042e-08,5.7706608718023995e-08
|
||||||
|
92,6.750649045006184e-05,1.435304906112738e-08,5.692499280974924e-08
|
||||||
|
93,6.659208967850971e-05,1.4233077472549144e-08,5.615392239861094e-08
|
||||||
|
94,6.554258932109723e-05,1.4075047005202515e-08,5.5268928972034715e-08
|
||||||
|
95,6.450957734109015e-05,1.3918652473373596e-08,5.439783940505763e-08
|
||||||
|
Binary file not shown.
@@ -1,806 +0,0 @@
|
|||||||
{
|
|
||||||
"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": "west fused spans in Corlay",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Corlay",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 2.0,
|
|
||||||
"longitude": 1.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "west fused spans in Loudeac",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Loudeac",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 2.0,
|
|
||||||
"longitude": 2.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "west fused spans in Morlaix",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Morlaix",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 3.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east fused spans in Corlay",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Corlay",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 2.0,
|
|
||||||
"longitude": 1.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east fused spans in Loudeac",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Loudeac",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 2.0,
|
|
||||||
"longitude": 2.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east fused spans in Morlaix",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Morlaix",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 3.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Corlay → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Loudeac → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lorient_KMA → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Stbrieuc → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Morlaix → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (toto → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Corlay → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Loudeac → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lorient_KMA → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Vannes_KBE → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Stbrieuc → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Rennes_STA → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Morlaix → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Brest_KLA → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (tata → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east 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,
|
|
||||||
"out_voa": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east 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,
|
|
||||||
"out_voa": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"connections": [
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "east edfa in Lannion_CAS to Corlay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east edfa in Lannion_CAS to Corlay",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Corlay)-F061"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Corlay → Lannion_CAS)-F061",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Stbrieuc)-F056"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Stbrieuc → Lannion_CAS)-F056",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Morlaix)-F059"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Morlaix → Lannion_CAS)-F059",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Corlay)-F061",
|
|
||||||
"to_node": "west fused spans in Corlay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "west fused spans in Corlay",
|
|
||||||
"to_node": "fiber (Corlay → Loudeac)-F010"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Loudeac → Corlay)-F010",
|
|
||||||
"to_node": "east fused spans in Corlay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east fused spans in Corlay",
|
|
||||||
"to_node": "fiber (Corlay → Lannion_CAS)-F061"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Corlay → Loudeac)-F010",
|
|
||||||
"to_node": "west fused spans in Loudeac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "west fused spans in Loudeac",
|
|
||||||
"to_node": "fiber (Loudeac → Lorient_KMA)-F054"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lorient_KMA → Loudeac)-F054",
|
|
||||||
"to_node": "east fused spans in Loudeac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east fused spans in Loudeac",
|
|
||||||
"to_node": "fiber (Loudeac → Corlay)-F010"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lorient_KMA",
|
|
||||||
"to_node": "east edfa in Lorient_KMA to Loudeac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east edfa in Lorient_KMA to Loudeac",
|
|
||||||
"to_node": "fiber (Lorient_KMA → Loudeac)-F054"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Loudeac → Lorient_KMA)-F054",
|
|
||||||
"to_node": "roadm Lorient_KMA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lorient_KMA",
|
|
||||||
"to_node": "fiber (Lorient_KMA → Vannes_KBE)-F055"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Vannes_KBE → Lorient_KMA)-F055",
|
|
||||||
"to_node": "roadm Lorient_KMA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Vannes_KBE",
|
|
||||||
"to_node": "fiber (Vannes_KBE → Lorient_KMA)-F055"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lorient_KMA → Vannes_KBE)-F055",
|
|
||||||
"to_node": "roadm Vannes_KBE"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Stbrieuc)-F056",
|
|
||||||
"to_node": "fiber (Stbrieuc → Rennes_STA)-F057"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Rennes_STA → Stbrieuc)-F057",
|
|
||||||
"to_node": "fiber (Stbrieuc → Lannion_CAS)-F056"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Rennes_STA",
|
|
||||||
"to_node": "fiber (Rennes_STA → Stbrieuc)-F057"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Stbrieuc → Rennes_STA)-F057",
|
|
||||||
"to_node": "roadm Rennes_STA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Morlaix)-F059",
|
|
||||||
"to_node": "west fused spans in Morlaix"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "west fused spans in Morlaix",
|
|
||||||
"to_node": "fiber (Morlaix → Brest_KLA)-F060"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Brest_KLA → Morlaix)-F060",
|
|
||||||
"to_node": "east fused spans in Morlaix"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east fused spans in Morlaix",
|
|
||||||
"to_node": "fiber (Morlaix → Lannion_CAS)-F059"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Brest_KLA",
|
|
||||||
"to_node": "fiber (Brest_KLA → Morlaix)-F060"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Morlaix → Brest_KLA)-F060",
|
|
||||||
"to_node": "roadm Brest_KLA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm toto",
|
|
||||||
"to_node": "fiber (toto → tata)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (tata → toto)-",
|
|
||||||
"to_node": "roadm toto"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm tata",
|
|
||||||
"to_node": "fiber (tata → toto)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (toto → 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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
{
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"synchronization": [
|
|
||||||
{
|
|
||||||
"synchronization-id": "0",
|
|
||||||
"svec": {
|
|
||||||
"relaxable": "False",
|
|
||||||
"link-diverse": "True",
|
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"synchronization-id": "3",
|
|
||||||
"svec": {
|
|
||||||
"relaxable": "False",
|
|
||||||
"link-diverse": "True",
|
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
|
||||||
"3",
|
|
||||||
"4"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"synchronization-id": "5",
|
|
||||||
"svec": {
|
|
||||||
"relaxable": "False",
|
|
||||||
"link-diverse": "True",
|
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
|
||||||
"5",
|
|
||||||
"0"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,762 +0,0 @@
|
|||||||
{
|
|
||||||
"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": "west fused spans in Corlay",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Corlay",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 2.0,
|
|
||||||
"longitude": 1.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "west fused spans in Loudeac",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Loudeac",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 2.0,
|
|
||||||
"longitude": 2.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "west fused spans in Morlaix",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Morlaix",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 3.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east fused spans in Corlay",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Corlay",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 2.0,
|
|
||||||
"longitude": 1.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east fused spans in Loudeac",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Loudeac",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 2.0,
|
|
||||||
"longitude": 2.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "east fused spans in Morlaix",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "Morlaix",
|
|
||||||
"region": "RLD",
|
|
||||||
"latitude": 3.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fused"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Corlay → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Loudeac → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lorient_KMA → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Stbrieuc → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lannion_CAS → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Morlaix → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (toto → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Corlay → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Loudeac → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Lorient_KMA → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Vannes_KBE → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Stbrieuc → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Rennes_STA → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Morlaix → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (Brest_KLA → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (tata → 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,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"connections": [
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Corlay)-F061"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Corlay → Lannion_CAS)-F061",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Stbrieuc)-F056"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Stbrieuc → Lannion_CAS)-F056",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lannion_CAS",
|
|
||||||
"to_node": "fiber (Lannion_CAS → Morlaix)-F059"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Morlaix → Lannion_CAS)-F059",
|
|
||||||
"to_node": "roadm Lannion_CAS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Corlay)-F061",
|
|
||||||
"to_node": "west fused spans in Corlay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "west fused spans in Corlay",
|
|
||||||
"to_node": "fiber (Corlay → Loudeac)-F010"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Loudeac → Corlay)-F010",
|
|
||||||
"to_node": "east fused spans in Corlay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east fused spans in Corlay",
|
|
||||||
"to_node": "fiber (Corlay → Lannion_CAS)-F061"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Corlay → Loudeac)-F010",
|
|
||||||
"to_node": "west fused spans in Loudeac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "west fused spans in Loudeac",
|
|
||||||
"to_node": "fiber (Loudeac → Lorient_KMA)-F054"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lorient_KMA → Loudeac)-F054",
|
|
||||||
"to_node": "east fused spans in Loudeac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east fused spans in Loudeac",
|
|
||||||
"to_node": "fiber (Loudeac → Corlay)-F010"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lorient_KMA",
|
|
||||||
"to_node": "fiber (Lorient_KMA → Loudeac)-F054"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Loudeac → Lorient_KMA)-F054",
|
|
||||||
"to_node": "roadm Lorient_KMA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Lorient_KMA",
|
|
||||||
"to_node": "fiber (Lorient_KMA → Vannes_KBE)-F055"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Vannes_KBE → Lorient_KMA)-F055",
|
|
||||||
"to_node": "roadm Lorient_KMA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Vannes_KBE",
|
|
||||||
"to_node": "fiber (Vannes_KBE → Lorient_KMA)-F055"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lorient_KMA → Vannes_KBE)-F055",
|
|
||||||
"to_node": "roadm Vannes_KBE"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Stbrieuc)-F056",
|
|
||||||
"to_node": "fiber (Stbrieuc → Rennes_STA)-F057"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Rennes_STA → Stbrieuc)-F057",
|
|
||||||
"to_node": "fiber (Stbrieuc → Lannion_CAS)-F056"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Rennes_STA",
|
|
||||||
"to_node": "fiber (Rennes_STA → Stbrieuc)-F057"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Stbrieuc → Rennes_STA)-F057",
|
|
||||||
"to_node": "roadm Rennes_STA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Lannion_CAS → Morlaix)-F059",
|
|
||||||
"to_node": "west fused spans in Morlaix"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "west fused spans in Morlaix",
|
|
||||||
"to_node": "fiber (Morlaix → Brest_KLA)-F060"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Brest_KLA → Morlaix)-F060",
|
|
||||||
"to_node": "east fused spans in Morlaix"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "east fused spans in Morlaix",
|
|
||||||
"to_node": "fiber (Morlaix → Lannion_CAS)-F059"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm Brest_KLA",
|
|
||||||
"to_node": "fiber (Brest_KLA → Morlaix)-F060"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (Morlaix → Brest_KLA)-F060",
|
|
||||||
"to_node": "roadm Brest_KLA"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm toto",
|
|
||||||
"to_node": "fiber (toto → tata)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (tata → toto)-",
|
|
||||||
"to_node": "roadm toto"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm tata",
|
|
||||||
"to_node": "fiber (tata → toto)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (toto → 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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
{
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"path_bandwidth": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"synchronization": [
|
|
||||||
{
|
|
||||||
"synchronization-id": "0",
|
|
||||||
"svec": {
|
|
||||||
"relaxable": "False",
|
|
||||||
"link-diverse": "True",
|
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"synchronization-id": "3",
|
|
||||||
"svec": {
|
|
||||||
"relaxable": "False",
|
|
||||||
"link-diverse": "True",
|
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
|
||||||
"3",
|
|
||||||
"4"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"synchronization-id": "5",
|
|
||||||
"svec": {
|
|
||||||
"relaxable": "False",
|
|
||||||
"link-diverse": "True",
|
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
|
||||||
"5",
|
|
||||||
"0"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,730 +0,0 @@
|
|||||||
{
|
|
||||||
"elements": [
|
|
||||||
{
|
|
||||||
"uid": "trx a",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "a",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx b",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "b",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx c",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "c",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx d",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "d",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx e",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "e",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx f",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "f",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx g",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "g",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "trx h",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "h",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Transceiver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm a",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "a",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm b",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "b",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm c",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "c",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm d",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "d",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm e",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "e",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm f",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "f",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm g",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "g",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "roadm h",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"city": "h",
|
|
||||||
"region": "",
|
|
||||||
"latitude": 0,
|
|
||||||
"longitude": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Roadm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (a \u2192 b)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 30.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (a \u2192 c)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 30.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (c \u2192 d)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 50.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (c \u2192 f)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 60.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (b \u2192 f)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 70.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (e \u2192 d)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 80.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (e \u2192 g)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 90.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (f \u2192 h)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 100.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (h \u2192 g)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 110.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (b \u2192 a)-F061",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 30.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (c \u2192 a)-F010",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 30.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (d \u2192 c)-F054",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 50.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (f \u2192 c)-F055",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 60.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (f \u2192 b)-F056",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 70.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (d \u2192 e)-F057",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 80.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (g \u2192 e)-F059",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 90.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (h \u2192 f)-F060",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 100.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "fiber (g \u2192 h)-",
|
|
||||||
"metadata": {
|
|
||||||
"location": {
|
|
||||||
"latitude": 0.0,
|
|
||||||
"longitude": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "Fiber",
|
|
||||||
"type_variety": "SSMF",
|
|
||||||
"params": {
|
|
||||||
"length": 110.0,
|
|
||||||
"length_units": "km",
|
|
||||||
"loss_coef": 0.2,
|
|
||||||
"con_in": null,
|
|
||||||
"con_out": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"connections": [
|
|
||||||
{
|
|
||||||
"from_node": "roadm a",
|
|
||||||
"to_node": "fiber (a \u2192 b)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (b \u2192 a)-F061",
|
|
||||||
"to_node": "roadm a"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm a",
|
|
||||||
"to_node": "fiber (a \u2192 c)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (c \u2192 a)-F010",
|
|
||||||
"to_node": "roadm a"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm b",
|
|
||||||
"to_node": "fiber (b \u2192 a)-F061"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (a \u2192 b)-",
|
|
||||||
"to_node": "roadm b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm b",
|
|
||||||
"to_node": "fiber (b \u2192 f)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (f \u2192 b)-F056",
|
|
||||||
"to_node": "roadm b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm c",
|
|
||||||
"to_node": "fiber (c \u2192 a)-F010"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (a \u2192 c)-",
|
|
||||||
"to_node": "roadm c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm c",
|
|
||||||
"to_node": "fiber (c \u2192 d)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (d \u2192 c)-F054",
|
|
||||||
"to_node": "roadm c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm c",
|
|
||||||
"to_node": "fiber (c \u2192 f)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (f \u2192 c)-F055",
|
|
||||||
"to_node": "roadm c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm d",
|
|
||||||
"to_node": "fiber (d \u2192 c)-F054"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (c \u2192 d)-",
|
|
||||||
"to_node": "roadm d"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm d",
|
|
||||||
"to_node": "fiber (d \u2192 e)-F057"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (e \u2192 d)-",
|
|
||||||
"to_node": "roadm d"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm e",
|
|
||||||
"to_node": "fiber (e \u2192 d)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (d \u2192 e)-F057",
|
|
||||||
"to_node": "roadm e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm e",
|
|
||||||
"to_node": "fiber (e \u2192 g)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (g \u2192 e)-F059",
|
|
||||||
"to_node": "roadm e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm f",
|
|
||||||
"to_node": "fiber (f \u2192 c)-F055"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (c \u2192 f)-",
|
|
||||||
"to_node": "roadm f"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm f",
|
|
||||||
"to_node": "fiber (f \u2192 b)-F056"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (b \u2192 f)-",
|
|
||||||
"to_node": "roadm f"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm f",
|
|
||||||
"to_node": "fiber (f \u2192 h)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (h \u2192 f)-F060",
|
|
||||||
"to_node": "roadm f"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm g",
|
|
||||||
"to_node": "fiber (g \u2192 e)-F059"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (e \u2192 g)-",
|
|
||||||
"to_node": "roadm g"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm g",
|
|
||||||
"to_node": "fiber (g \u2192 h)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (h \u2192 g)-",
|
|
||||||
"to_node": "roadm g"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm h",
|
|
||||||
"to_node": "fiber (h \u2192 f)-F060"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (f \u2192 h)-",
|
|
||||||
"to_node": "roadm h"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm h",
|
|
||||||
"to_node": "fiber (h \u2192 g)-"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "fiber (g \u2192 h)-",
|
|
||||||
"to_node": "roadm h"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "trx a",
|
|
||||||
"to_node": "roadm a"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm a",
|
|
||||||
"to_node": "trx a"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "trx b",
|
|
||||||
"to_node": "roadm b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm b",
|
|
||||||
"to_node": "trx b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "trx c",
|
|
||||||
"to_node": "roadm c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm c",
|
|
||||||
"to_node": "trx c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "trx d",
|
|
||||||
"to_node": "roadm d"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm d",
|
|
||||||
"to_node": "trx d"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "trx e",
|
|
||||||
"to_node": "roadm e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm e",
|
|
||||||
"to_node": "trx e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "trx f",
|
|
||||||
"to_node": "roadm f"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm f",
|
|
||||||
"to_node": "trx f"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "trx g",
|
|
||||||
"to_node": "roadm g"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm g",
|
|
||||||
"to_node": "trx g"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "trx h",
|
|
||||||
"to_node": "roadm h"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from_node": "roadm h",
|
|
||||||
"to_node": "trx h"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
223
tests/data/raman_fiber_config.json
Normal file
223
tests/data/raman_fiber_config.json
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
{
|
||||||
|
"uid": "Span1",
|
||||||
|
"params": {
|
||||||
|
"length": 80,
|
||||||
|
"loss_coef": 0.2,
|
||||||
|
"length_units": "km",
|
||||||
|
"att_in": 0,
|
||||||
|
"con_in": 0.5,
|
||||||
|
"con_out": 0.5,
|
||||||
|
"type_variety": "SSMF",
|
||||||
|
"dispersion": 0.0000167,
|
||||||
|
"gamma": 0.00127,
|
||||||
|
"raman_efficiency": {
|
||||||
|
"cr": [
|
||||||
|
0,
|
||||||
|
0.0000094,
|
||||||
|
0.0000292,
|
||||||
|
0.0000488,
|
||||||
|
0.0000682,
|
||||||
|
0.0000831,
|
||||||
|
0.000094,
|
||||||
|
0.0001014,
|
||||||
|
0.0001069,
|
||||||
|
0.0001119,
|
||||||
|
0.0001217,
|
||||||
|
0.0001268,
|
||||||
|
0.0001365,
|
||||||
|
0.000149,
|
||||||
|
0.000165,
|
||||||
|
0.000181,
|
||||||
|
0.0001977,
|
||||||
|
0.0002192,
|
||||||
|
0.0002469,
|
||||||
|
0.0002749,
|
||||||
|
0.0002999,
|
||||||
|
0.0003206,
|
||||||
|
0.0003405,
|
||||||
|
0.0003592,
|
||||||
|
0.000374,
|
||||||
|
0.0003826,
|
||||||
|
0.0003841,
|
||||||
|
0.0003826,
|
||||||
|
0.0003802,
|
||||||
|
0.0003756,
|
||||||
|
0.0003549,
|
||||||
|
0.0003795,
|
||||||
|
0.000344,
|
||||||
|
0.0002933,
|
||||||
|
0.0002024,
|
||||||
|
0.0001158,
|
||||||
|
0.0000846,
|
||||||
|
0.0000714,
|
||||||
|
0.0000686,
|
||||||
|
0.000085,
|
||||||
|
0.0000893,
|
||||||
|
0.0000901,
|
||||||
|
0.0000815,
|
||||||
|
0.0000667,
|
||||||
|
0.0000437,
|
||||||
|
0.0000328,
|
||||||
|
0.0000296,
|
||||||
|
0.0000265,
|
||||||
|
0.0000257,
|
||||||
|
0.0000281,
|
||||||
|
0.0000308,
|
||||||
|
0.0000367,
|
||||||
|
0.0000585,
|
||||||
|
0.0000663,
|
||||||
|
0.0000636,
|
||||||
|
0.000055,
|
||||||
|
0.0000406,
|
||||||
|
0.0000277,
|
||||||
|
0.0000242,
|
||||||
|
0.0000187,
|
||||||
|
0.000016,
|
||||||
|
0.000014,
|
||||||
|
0.0000113,
|
||||||
|
0.0000105,
|
||||||
|
0.0000098,
|
||||||
|
0.0000098,
|
||||||
|
0.0000113,
|
||||||
|
0.0000164,
|
||||||
|
0.0000195,
|
||||||
|
0.0000238,
|
||||||
|
0.0000226,
|
||||||
|
0.0000203,
|
||||||
|
0.0000148,
|
||||||
|
0.0000109,
|
||||||
|
0.0000098,
|
||||||
|
0.0000105,
|
||||||
|
0.0000117,
|
||||||
|
0.0000125,
|
||||||
|
0.0000121,
|
||||||
|
0.0000109,
|
||||||
|
0.0000098,
|
||||||
|
0.0000082,
|
||||||
|
0.0000066,
|
||||||
|
0.0000047,
|
||||||
|
0.0000027,
|
||||||
|
0.0000019,
|
||||||
|
0.0000012,
|
||||||
|
4e-7,
|
||||||
|
2e-7,
|
||||||
|
1e-7
|
||||||
|
],
|
||||||
|
"frequency_offset": [
|
||||||
|
0,
|
||||||
|
500000000000,
|
||||||
|
1000000000000,
|
||||||
|
1500000000000,
|
||||||
|
2000000000000,
|
||||||
|
2500000000000,
|
||||||
|
3000000000000,
|
||||||
|
3500000000000,
|
||||||
|
4000000000000,
|
||||||
|
4500000000000,
|
||||||
|
5000000000000,
|
||||||
|
5500000000000,
|
||||||
|
6000000000000,
|
||||||
|
6500000000000,
|
||||||
|
7000000000000,
|
||||||
|
7500000000000,
|
||||||
|
8000000000000,
|
||||||
|
8500000000000,
|
||||||
|
9000000000000,
|
||||||
|
9500000000000,
|
||||||
|
10000000000000,
|
||||||
|
10500000000000,
|
||||||
|
11000000000000,
|
||||||
|
11500000000000,
|
||||||
|
12000000000000,
|
||||||
|
12500000000000,
|
||||||
|
12750000000000,
|
||||||
|
13000000000000,
|
||||||
|
13250000000000,
|
||||||
|
13500000000000,
|
||||||
|
14000000000000,
|
||||||
|
14500000000000,
|
||||||
|
14750000000000,
|
||||||
|
15000000000000,
|
||||||
|
15500000000000,
|
||||||
|
16000000000000,
|
||||||
|
16500000000000,
|
||||||
|
17000000000000,
|
||||||
|
17500000000000,
|
||||||
|
18000000000000,
|
||||||
|
18250000000000,
|
||||||
|
18500000000000,
|
||||||
|
18750000000000,
|
||||||
|
19000000000000,
|
||||||
|
19500000000000,
|
||||||
|
20000000000000,
|
||||||
|
20500000000000,
|
||||||
|
21000000000000,
|
||||||
|
21500000000000,
|
||||||
|
22000000000000,
|
||||||
|
22500000000000,
|
||||||
|
23000000000000,
|
||||||
|
23500000000000,
|
||||||
|
24000000000000,
|
||||||
|
24500000000000,
|
||||||
|
25000000000000,
|
||||||
|
25500000000000,
|
||||||
|
26000000000000,
|
||||||
|
26500000000000,
|
||||||
|
27000000000000,
|
||||||
|
27500000000000,
|
||||||
|
28000000000000,
|
||||||
|
28500000000000,
|
||||||
|
29000000000000,
|
||||||
|
29500000000000,
|
||||||
|
30000000000000,
|
||||||
|
30500000000000,
|
||||||
|
31000000000000,
|
||||||
|
31500000000000,
|
||||||
|
32000000000000,
|
||||||
|
32500000000000,
|
||||||
|
33000000000000,
|
||||||
|
33500000000000,
|
||||||
|
34000000000000,
|
||||||
|
34500000000000,
|
||||||
|
35000000000000,
|
||||||
|
35500000000000,
|
||||||
|
36000000000000,
|
||||||
|
36500000000000,
|
||||||
|
37000000000000,
|
||||||
|
37500000000000,
|
||||||
|
38000000000000,
|
||||||
|
38500000000000,
|
||||||
|
39000000000000,
|
||||||
|
39500000000000,
|
||||||
|
40000000000000,
|
||||||
|
40500000000000,
|
||||||
|
41000000000000,
|
||||||
|
41500000000000,
|
||||||
|
42000000000000
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operational": {
|
||||||
|
"temperature": 283,
|
||||||
|
"raman_pumps": [
|
||||||
|
{
|
||||||
|
"power": 0.2,
|
||||||
|
"frequency": 205000000000000,
|
||||||
|
"propagation_direction": "counterprop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"power": 0.206,
|
||||||
|
"frequency": 201000000000000,
|
||||||
|
"propagation_direction": "counterprop"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"latitude": 1,
|
||||||
|
"longitude": 0,
|
||||||
|
"city": null,
|
||||||
|
"region": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
tests/data/sim_params.json
Normal file
14
tests/data/sim_params.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"raman_computed_channels": [1, 18, 37, 56, 75],
|
||||||
|
"raman_parameters": {
|
||||||
|
"flag_raman": true,
|
||||||
|
"space_resolution": 10e3,
|
||||||
|
"tolerance": 1e-8
|
||||||
|
},
|
||||||
|
"nli_parameters": {
|
||||||
|
"nli_method_name": "ggn_spectrally_separated",
|
||||||
|
"wdm_grid_size": 50e9,
|
||||||
|
"dispersion_tolerance": 1,
|
||||||
|
"phase_shift_tollerance": 0.1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
tests/data/testService.xls
Normal file
BIN
tests/data/testService.xls
Normal file
Binary file not shown.
79
tests/data/testService_services_expected.json
Normal file
79
tests/data/testService_services_expected.json
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"path-request": [
|
||||||
|
{
|
||||||
|
"request-id": "0",
|
||||||
|
"source": "trx Lorient_KMA",
|
||||||
|
"destination": "trx Vannes_KBE",
|
||||||
|
"src-tp-id": "trx Lorient_KMA",
|
||||||
|
"dst-tp-id": "trx Vannes_KBE",
|
||||||
|
"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": 80,
|
||||||
|
"output-power": null,
|
||||||
|
"path_bandwidth": 100000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"request-id": "1",
|
||||||
|
"source": "trx Brest_KLA",
|
||||||
|
"destination": "trx Vannes_KBE",
|
||||||
|
"src-tp-id": "trx Brest_KLA",
|
||||||
|
"dst-tp-id": "trx Vannes_KBE",
|
||||||
|
"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": 0.0012589254117941673,
|
||||||
|
"path_bandwidth": 10000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"request-id": "3",
|
||||||
|
"source": "trx Lannion_CAS",
|
||||||
|
"destination": "trx Rennes_STA",
|
||||||
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
|
"dst-tp-id": "trx Rennes_STA",
|
||||||
|
"bidirectional": false,
|
||||||
|
"path-constraints": {
|
||||||
|
"te-bandwidth": {
|
||||||
|
"technology": "flexi-grid",
|
||||||
|
"trx_type": "vendorA_trx-type1",
|
||||||
|
"trx_mode": "mode 1",
|
||||||
|
"effective-freq-slot": [
|
||||||
|
{
|
||||||
|
"N": "null",
|
||||||
|
"M": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"spacing": 50000000000.0,
|
||||||
|
"max-nb-of-channel": 80,
|
||||||
|
"output-power": 0.0012589254117941673,
|
||||||
|
"path_bandwidth": 60000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
tests/data/testTopology.xls
Normal file
BIN
tests/data/testTopology.xls
Normal file
Binary file not shown.
3357
tests/data/testTopology_auto_design_expected.json
Normal file
3357
tests/data/testTopology_auto_design_expected.json
Normal file
File diff suppressed because it is too large
Load Diff
1781
tests/data/testTopology_expected.json
Normal file
1781
tests/data/testTopology_expected.json
Normal file
File diff suppressed because it is too large
Load Diff
1471
tests/data/testTopology_response.json
Normal file
1471
tests/data/testTopology_response.json
Normal file
File diff suppressed because it is too large
Load Diff
8
tests/data/testTopology_response_expected.csv
Normal file
8
tests/data/testTopology_response_expected.csv
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
response-id,source,destination,path_bandwidth,Pass?,nb of tsp pairs,total cost,transponder-type,transponder-mode,OSNR-0.1nm,SNR-0.1nm,SNR-bandwidth,baud rate (Gbaud),input power (dBm),path,"spectrum (N,M)",reversed path OSNR-0.1nm,reversed path SNR-0.1nm,reversed path SNR-bandwidth
|
||||||
|
0,trx Lorient_KMA,trx Vannes_KBE,100.0,True,1,1,Voyager,mode 1,30.84,30.84,26.75,32.0,0.0,trx Lorient_KMA | roadm Lorient_KMA | Edfa1_roadm Lorient_KMA | fiber (Lorient_KMA → Vannes_KBE)-F055 | Edfa0_fiber (Lorient_KMA → Vannes_KBE)-F055 | roadm Vannes_KBE | trx Vannes_KBE,"-284, 4"
|
||||||
|
1,trx Brest_KLA,trx Vannes_KBE,10.0,True,1,1,Voyager,mode 1,22.65,22.11,18.03,32.0,1.0,trx Brest_KLA | roadm Brest_KLA | Edfa0_roadm Brest_KLA | fiber (Brest_KLA → Morlaix)-F060 | east fused spans in Morlaix | fiber (Morlaix → Lannion_CAS)-F059 | west edfa in Lannion_CAS to Morlaix | roadm Lannion_CAS | east edfa in Lannion_CAS to Corlay | fiber (Lannion_CAS → Corlay)-F061 | west fused spans in Corlay | fiber (Corlay → Loudeac)-F010 | west fused spans in Loudeac | fiber (Loudeac → Lorient_KMA)-F054 | Edfa0_fiber (Loudeac → Lorient_KMA)-F054 | roadm Lorient_KMA | Edfa1_roadm Lorient_KMA | fiber (Lorient_KMA → Vannes_KBE)-F055 | Edfa0_fiber (Lorient_KMA → Vannes_KBE)-F055 | roadm Vannes_KBE | trx Vannes_KBE,"-276, 4"
|
||||||
|
3,trx Lannion_CAS,trx Rennes_STA,60.0,True,1,1,vendorA_trx-type1,mode 1,28.29,25.85,21.77,32.0,1.0,trx Lannion_CAS | roadm Lannion_CAS | east edfa in Lannion_CAS to Stbrieuc | fiber (Lannion_CAS → Stbrieuc)-F056 | east edfa in Stbrieuc to Rennes_STA | fiber (Stbrieuc → Rennes_STA)-F057 | Edfa0_fiber (Stbrieuc → Rennes_STA)-F057 | roadm Rennes_STA | trx Rennes_STA,"-284, 4"
|
||||||
|
4,trx Rennes_STA,trx Lannion_CAS,150.0,True,1,1,vendorA_trx-type1,mode 2,22.27,22.15,15.05,64.0,0.0,trx Rennes_STA | roadm Rennes_STA | Edfa1_roadm Rennes_STA | fiber (Rennes_STA → Ploermel)- | east edfa in Ploermel to Vannes_KBE | fiber (Ploermel → Vannes_KBE)- | Edfa0_fiber (Ploermel → Vannes_KBE)- | roadm Vannes_KBE | Edfa0_roadm Vannes_KBE | fiber (Vannes_KBE → Lorient_KMA)-F055 | Edfa0_fiber (Vannes_KBE → Lorient_KMA)-F055 | roadm Lorient_KMA | Edfa0_roadm Lorient_KMA | fiber (Lorient_KMA → Loudeac)-F054 | east fused spans in Loudeac | fiber (Loudeac → Corlay)-F010 | east fused spans in Corlay | fiber (Corlay → Lannion_CAS)-F061 | west edfa in Lannion_CAS to Corlay | roadm Lannion_CAS | trx Lannion_CAS,"-266, 6"
|
||||||
|
5,trx Rennes_STA,trx Lannion_CAS,20.0,True,1,1,vendorA_trx-type1,mode 2,30.79,28.77,21.68,64.0,3.0,trx Rennes_STA | roadm Rennes_STA | Edfa0_roadm Rennes_STA | fiber (Rennes_STA → Stbrieuc)-F057 | Edfa0_fiber (Rennes_STA → Stbrieuc)-F057 | fiber (Stbrieuc → Lannion_CAS)-F056 | Edfa0_fiber (Stbrieuc → Lannion_CAS)-F056 | roadm Lannion_CAS | trx Lannion_CAS,"-274, 6"
|
||||||
|
6,,,,NO_PATH,,,,,,,,,,,
|
||||||
|
|
||||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
218
tests/data/testTopology_services_expected.json
Normal file
218
tests/data/testTopology_services_expected.json
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
{
|
||||||
|
"path-request": [
|
||||||
|
{
|
||||||
|
"request-id": "0",
|
||||||
|
"source": "trx Lorient_KMA",
|
||||||
|
"destination": "trx Vannes_KBE",
|
||||||
|
"src-tp-id": "trx Lorient_KMA",
|
||||||
|
"dst-tp-id": "trx Vannes_KBE",
|
||||||
|
"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": 80,
|
||||||
|
"output-power": null,
|
||||||
|
"path_bandwidth": 100000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"request-id": "1",
|
||||||
|
"source": "trx Brest_KLA",
|
||||||
|
"destination": "trx Vannes_KBE",
|
||||||
|
"src-tp-id": "trx Brest_KLA",
|
||||||
|
"dst-tp-id": "trx Vannes_KBE",
|
||||||
|
"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": 0.0012589254117941673,
|
||||||
|
"path_bandwidth": 10000000000.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"explicit-route-objects": {
|
||||||
|
"route-object-include-exclude": [
|
||||||
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
|
"index": 0,
|
||||||
|
"num-unnum-hop": {
|
||||||
|
"node-id": "roadm Brest_KLA",
|
||||||
|
"link-tp-id": "link-tp-id is not used",
|
||||||
|
"hop-type": "LOOSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
|
"index": 1,
|
||||||
|
"num-unnum-hop": {
|
||||||
|
"node-id": "roadm Lannion_CAS",
|
||||||
|
"link-tp-id": "link-tp-id is not used",
|
||||||
|
"hop-type": "LOOSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
|
"index": 2,
|
||||||
|
"num-unnum-hop": {
|
||||||
|
"node-id": "roadm Lorient_KMA",
|
||||||
|
"link-tp-id": "link-tp-id is not used",
|
||||||
|
"hop-type": "LOOSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
|
"index": 3,
|
||||||
|
"num-unnum-hop": {
|
||||||
|
"node-id": "roadm Vannes_KBE",
|
||||||
|
"link-tp-id": "link-tp-id is not used",
|
||||||
|
"hop-type": "LOOSE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"request-id": "3",
|
||||||
|
"source": "trx Lannion_CAS",
|
||||||
|
"destination": "trx Rennes_STA",
|
||||||
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
|
"dst-tp-id": "trx Rennes_STA",
|
||||||
|
"bidirectional": false,
|
||||||
|
"path-constraints": {
|
||||||
|
"te-bandwidth": {
|
||||||
|
"technology": "flexi-grid",
|
||||||
|
"trx_type": "vendorA_trx-type1",
|
||||||
|
"trx_mode": "mode 1",
|
||||||
|
"effective-freq-slot": [
|
||||||
|
{
|
||||||
|
"N": "null",
|
||||||
|
"M": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"spacing": 50000000000.0,
|
||||||
|
"max-nb-of-channel": 80,
|
||||||
|
"output-power": 0.0012589254117941673,
|
||||||
|
"path_bandwidth": 60000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"request-id": "4",
|
||||||
|
"source": "trx Rennes_STA",
|
||||||
|
"destination": "trx Lannion_CAS",
|
||||||
|
"src-tp-id": "trx Rennes_STA",
|
||||||
|
"dst-tp-id": "trx Lannion_CAS",
|
||||||
|
"bidirectional": false,
|
||||||
|
"path-constraints": {
|
||||||
|
"te-bandwidth": {
|
||||||
|
"technology": "flexi-grid",
|
||||||
|
"trx_type": "vendorA_trx-type1",
|
||||||
|
"trx_mode": "mode 2",
|
||||||
|
"effective-freq-slot": [
|
||||||
|
{
|
||||||
|
"N": "null",
|
||||||
|
"M": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"spacing": 75000000000.0,
|
||||||
|
"max-nb-of-channel": null,
|
||||||
|
"output-power": null,
|
||||||
|
"path_bandwidth": 150000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"request-id": "5",
|
||||||
|
"source": "trx Rennes_STA",
|
||||||
|
"destination": "trx Lannion_CAS",
|
||||||
|
"src-tp-id": "trx Rennes_STA",
|
||||||
|
"dst-tp-id": "trx Lannion_CAS",
|
||||||
|
"bidirectional": false,
|
||||||
|
"path-constraints": {
|
||||||
|
"te-bandwidth": {
|
||||||
|
"technology": "flexi-grid",
|
||||||
|
"trx_type": "vendorA_trx-type1",
|
||||||
|
"trx_mode": "mode 2",
|
||||||
|
"effective-freq-slot": [
|
||||||
|
{
|
||||||
|
"N": "null",
|
||||||
|
"M": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"spacing": 75000000000.0,
|
||||||
|
"max-nb-of-channel": 63,
|
||||||
|
"output-power": 0.0019952623149688794,
|
||||||
|
"path_bandwidth": 20000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"request-id": "6",
|
||||||
|
"source": "trx Lannion_CAS",
|
||||||
|
"destination": "trx a",
|
||||||
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
|
"dst-tp-id": "trx a",
|
||||||
|
"bidirectional": false,
|
||||||
|
"path-constraints": {
|
||||||
|
"te-bandwidth": {
|
||||||
|
"technology": "flexi-grid",
|
||||||
|
"trx_type": "vendorA_trx-type1",
|
||||||
|
"trx_mode": "mode 2",
|
||||||
|
"effective-freq-slot": [
|
||||||
|
{
|
||||||
|
"N": "null",
|
||||||
|
"M": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"spacing": 75000000000.0,
|
||||||
|
"max-nb-of-channel": null,
|
||||||
|
"output-power": null,
|
||||||
|
"path_bandwidth": 100000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"synchronization": [
|
||||||
|
{
|
||||||
|
"synchronization-id": "3",
|
||||||
|
"svec": {
|
||||||
|
"relaxable": "false",
|
||||||
|
"disjointness": "node link",
|
||||||
|
"request-id-number": [
|
||||||
|
"3",
|
||||||
|
"1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"synchronization-id": "4",
|
||||||
|
"svec": {
|
||||||
|
"relaxable": "false",
|
||||||
|
"disjointness": "node link",
|
||||||
|
"request-id-number": [
|
||||||
|
"4",
|
||||||
|
"5"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -2,10 +2,11 @@
|
|||||||
"path-request": [
|
"path-request": [
|
||||||
{
|
{
|
||||||
"request-id": "1",
|
"request-id": "1",
|
||||||
"source": "a",
|
"source": "trx a",
|
||||||
"destination": "g",
|
"destination": "trx g",
|
||||||
"src-tp-id": "trx a",
|
"src-tp-id": "trx a",
|
||||||
"dst-tp-id": "trx g",
|
"dst-tp-id": "trx g",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -22,17 +23,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "2a",
|
"request-id": "2a",
|
||||||
"source": "a",
|
"source": "trx a",
|
||||||
"destination": "h",
|
"destination": "trx h",
|
||||||
"src-tp-id": "trx a",
|
"src-tp-id": "trx a",
|
||||||
"dst-tp-id": "trx h",
|
"dst-tp-id": "trx h",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -49,17 +48,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "3",
|
"request-id": "3",
|
||||||
"source": "f",
|
"source": "trx f",
|
||||||
"destination": "b",
|
"destination": "trx b",
|
||||||
"src-tp-id": "trx f",
|
"src-tp-id": "trx f",
|
||||||
"dst-tp-id": "trx b",
|
"dst-tp-id": "trx b",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -76,17 +73,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "ee",
|
"request-id": "ee",
|
||||||
"source": "c",
|
"source": "trx c",
|
||||||
"destination": "f",
|
"destination": "trx f",
|
||||||
"src-tp-id": "trx c",
|
"src-tp-id": "trx c",
|
||||||
"dst-tp-id": "trx f",
|
"dst-tp-id": "trx f",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -104,36 +99,23 @@
|
|||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimizations": {
|
"explicit-route-objects": {
|
||||||
"explicit-route-include-objects": [
|
"route-object-include-exclude": [
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm e",
|
"node-id": "roadm e",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"hop-type": "LOOSE"
|
||||||
"hop-type": "loose",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 1,
|
"index": 1,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm g",
|
"node-id": "roadm g",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -141,10 +123,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "ff",
|
"request-id": "ff",
|
||||||
"source": "c",
|
"source": "trx c",
|
||||||
"destination": "f",
|
"destination": "trx f",
|
||||||
"src-tp-id": "trx c",
|
"src-tp-id": "trx c",
|
||||||
"dst-tp-id": "trx f",
|
"dst-tp-id": "trx f",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -161,17 +144,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "10",
|
"request-id": "10",
|
||||||
"source": "a",
|
"source": "trx a",
|
||||||
"destination": "g",
|
"destination": "trx g",
|
||||||
"src-tp-id": "trx a",
|
"src-tp-id": "trx a",
|
||||||
"dst-tp-id": "trx g",
|
"dst-tp-id": "trx g",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -188,17 +169,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "11",
|
"request-id": "11",
|
||||||
"source": "a",
|
"source": "trx a",
|
||||||
"destination": "h",
|
"destination": "trx h",
|
||||||
"src-tp-id": "trx a",
|
"src-tp-id": "trx a",
|
||||||
"dst-tp-id": "trx h",
|
"dst-tp-id": "trx h",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -216,21 +195,15 @@
|
|||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimizations": {
|
"explicit-route-objects": {
|
||||||
"explicit-route-include-objects": [
|
"route-object-include-exclude": [
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "bb",
|
"node-id": "bb",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -238,10 +211,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "12",
|
"request-id": "12",
|
||||||
"source": "f",
|
"source": "trx f",
|
||||||
"destination": "b",
|
"destination": "trx b",
|
||||||
"src-tp-id": "trx f",
|
"src-tp-id": "trx f",
|
||||||
"dst-tp-id": "trx b",
|
"dst-tp-id": "trx b",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -259,21 +233,15 @@
|
|||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimizations": {
|
"explicit-route-objects": {
|
||||||
"explicit-route-include-objects": [
|
"route-object-include-exclude": [
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "trx b",
|
"node-id": "trx b",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -281,10 +249,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "13",
|
"request-id": "13",
|
||||||
"source": "c",
|
"source": "trx c",
|
||||||
"destination": "f",
|
"destination": "trx f",
|
||||||
"src-tp-id": "trx c",
|
"src-tp-id": "trx c",
|
||||||
"dst-tp-id": "trx f",
|
"dst-tp-id": "trx f",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -301,17 +270,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "14",
|
"request-id": "14",
|
||||||
"source": "c",
|
"source": "trx c",
|
||||||
"destination": "f",
|
"destination": "trx f",
|
||||||
"src-tp-id": "trx c",
|
"src-tp-id": "trx c",
|
||||||
"dst-tp-id": "trx f",
|
"dst-tp-id": "trx f",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -329,36 +296,23 @@
|
|||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimizations": {
|
"explicit-route-objects": {
|
||||||
"explicit-route-include-objects": [
|
"route-object-include-exclude": [
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm e",
|
"node-id": "roadm e",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"hop-type": "LOOSE"
|
||||||
"hop-type": "loose",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 1,
|
"index": 1,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm g",
|
"node-id": "roadm g",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -366,10 +320,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "e:1# /",
|
"request-id": "e:1# /",
|
||||||
"source": "a",
|
"source": "trx a",
|
||||||
"destination": "g",
|
"destination": "trx g",
|
||||||
"src-tp-id": "trx a",
|
"src-tp-id": "trx a",
|
||||||
"dst-tp-id": "trx g",
|
"dst-tp-id": "trx g",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -386,17 +341,15 @@
|
|||||||
"output-power": null,
|
"output-power": null,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "b-2a",
|
"request-id": "b-2a",
|
||||||
"source": "a",
|
"source": "trx a",
|
||||||
"destination": "h",
|
"destination": "trx h",
|
||||||
"src-tp-id": "trx a",
|
"src-tp-id": "trx a",
|
||||||
"dst-tp-id": "trx h",
|
"dst-tp-id": "trx h",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -413,17 +366,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "3a;?",
|
"request-id": "3a;?",
|
||||||
"source": "f",
|
"source": "trx f",
|
||||||
"destination": "b",
|
"destination": "trx b",
|
||||||
"src-tp-id": "trx f",
|
"src-tp-id": "trx f",
|
||||||
"dst-tp-id": "trx b",
|
"dst-tp-id": "trx b",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -440,17 +391,15 @@
|
|||||||
"output-power": null,
|
"output-power": null,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "ee-s",
|
"request-id": "ee-s",
|
||||||
"source": "c",
|
"source": "trx c",
|
||||||
"destination": "f",
|
"destination": "trx f",
|
||||||
"src-tp-id": "trx c",
|
"src-tp-id": "trx c",
|
||||||
"dst-tp-id": "trx f",
|
"dst-tp-id": "trx f",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -468,36 +417,23 @@
|
|||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimizations": {
|
"explicit-route-objects": {
|
||||||
"explicit-route-include-objects": [
|
"route-object-include-exclude": [
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm e",
|
"node-id": "roadm e",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"hop-type": "LOOSE"
|
||||||
"hop-type": "loose",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"explicit-route-usage": "route-include-ero",
|
||||||
"index": 1,
|
"index": 1,
|
||||||
"unnumbered-hop": {
|
"num-unnum-hop": {
|
||||||
"node-id": "roadm g",
|
"node-id": "roadm g",
|
||||||
"link-tp-id": "link-tp-id is not used",
|
"link-tp-id": "link-tp-id is not used",
|
||||||
"hop-type": "loose",
|
"hop-type": "LOOSE"
|
||||||
"direction": "direction is not used"
|
|
||||||
},
|
|
||||||
"label-hop": {
|
|
||||||
"te-label": {
|
|
||||||
"generic": "generic is not used",
|
|
||||||
"direction": "direction is not used"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -505,10 +441,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "ff-b",
|
"request-id": "ff-b",
|
||||||
"source": "c",
|
"source": "trx c",
|
||||||
"destination": "f",
|
"destination": "trx f",
|
||||||
"src-tp-id": "trx c",
|
"src-tp-id": "trx c",
|
||||||
"dst-tp-id": "trx f",
|
"dst-tp-id": "trx f",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -525,17 +462,15 @@
|
|||||||
"output-power": 0.001,
|
"output-power": 0.001,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "10-z",
|
"request-id": "10-z",
|
||||||
"source": "a",
|
"source": "trx a",
|
||||||
"destination": "g",
|
"destination": "trx g",
|
||||||
"src-tp-id": "trx a",
|
"src-tp-id": "trx a",
|
||||||
"dst-tp-id": "trx g",
|
"dst-tp-id": "trx g",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -552,17 +487,15 @@
|
|||||||
"output-power": null,
|
"output-power": null,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "11 g",
|
"request-id": "11 g",
|
||||||
"source": "a",
|
"source": "trx a",
|
||||||
"destination": "h",
|
"destination": "trx h",
|
||||||
"src-tp-id": "trx a",
|
"src-tp-id": "trx a",
|
||||||
"dst-tp-id": "trx h",
|
"dst-tp-id": "trx h",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -579,17 +512,15 @@
|
|||||||
"output-power": null,
|
"output-power": null,
|
||||||
"path_bandwidth": 300000000000.0
|
"path_bandwidth": 300000000000.0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "12<",
|
"request-id": "12<",
|
||||||
"source": "f",
|
"source": "trx f",
|
||||||
"destination": "b",
|
"destination": "trx b",
|
||||||
"src-tp-id": "trx f",
|
"src-tp-id": "trx f",
|
||||||
"dst-tp-id": "trx b",
|
"dst-tp-id": "trx b",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -606,17 +537,15 @@
|
|||||||
"output-power": null,
|
"output-power": null,
|
||||||
"path_bandwidth": null
|
"path_bandwidth": null
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": "12>",
|
"request-id": "12>",
|
||||||
"source": "f",
|
"source": "trx f",
|
||||||
"destination": "b",
|
"destination": "trx b",
|
||||||
"src-tp-id": "trx f",
|
"src-tp-id": "trx f",
|
||||||
"dst-tp-id": "trx b",
|
"dst-tp-id": "trx b",
|
||||||
|
"bidirectional": false,
|
||||||
"path-constraints": {
|
"path-constraints": {
|
||||||
"te-bandwidth": {
|
"te-bandwidth": {
|
||||||
"technology": "flexi-grid",
|
"technology": "flexi-grid",
|
||||||
@@ -633,9 +562,6 @@
|
|||||||
"output-power": null,
|
"output-power": null,
|
||||||
"path_bandwidth": null
|
"path_bandwidth": null
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"optimizations": {
|
|
||||||
"explicit-route-include-objects": []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -644,8 +570,7 @@
|
|||||||
"synchronization-id": "1",
|
"synchronization-id": "1",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"disjointness": "node link",
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
"1",
|
"1",
|
||||||
"2a"
|
"2a"
|
||||||
@@ -656,8 +581,7 @@
|
|||||||
"synchronization-id": "3",
|
"synchronization-id": "3",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"disjointness": "node link",
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
"3",
|
"3",
|
||||||
"1"
|
"1"
|
||||||
@@ -668,8 +592,7 @@
|
|||||||
"synchronization-id": "ff",
|
"synchronization-id": "ff",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"disjointness": "node link",
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
"ff",
|
"ff",
|
||||||
"13"
|
"13"
|
||||||
@@ -680,8 +603,7 @@
|
|||||||
"synchronization-id": "13",
|
"synchronization-id": "13",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"disjointness": "node link",
|
||||||
"node-diverse": "True",
|
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
"13",
|
"13",
|
||||||
"14"
|
"14"
|
||||||
@@ -78,6 +78,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"uid": "Att_B",
|
||||||
|
"type": "Fused",
|
||||||
|
"params":{
|
||||||
|
"loss":16
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 1.0,
|
||||||
|
"city": "Corlay",
|
||||||
|
"region": "RLD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"uid": "Site_B",
|
"uid": "Site_B",
|
||||||
"type": "Transceiver",
|
"type": "Transceiver",
|
||||||
@@ -110,6 +125,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "Edfa2",
|
"from_node": "Edfa2",
|
||||||
|
"to_node": "Att_B"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "Att_B",
|
||||||
"to_node": "Site_B"
|
"to_node": "Site_B"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ from json import load
|
|||||||
from gnpy.core.elements import Transceiver, Fiber, Edfa
|
from gnpy.core.elements import Transceiver, Fiber, Edfa
|
||||||
from gnpy.core.utils import lin2db, db2lin
|
from gnpy.core.utils import lin2db, db2lin
|
||||||
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power, Pref
|
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power, Pref
|
||||||
from gnpy.core.equipment import load_equipment, automatic_fmax
|
from gnpy.core.equipment import load_equipment, automatic_fmax, automatic_nch
|
||||||
from gnpy.core.network import build_network, load_network, set_roadm_loss
|
from gnpy.core.network import build_network, load_network
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ def test_variable_gain_nf(gain, nf_expected, setup_edfa_variable_gain, si):
|
|||||||
pin = pin/db2lin(gain)
|
pin = pin/db2lin(gain)
|
||||||
baud_rates = array([c.baud_rate for c in si.carriers])
|
baud_rates = array([c.baud_rate for c in si.carriers])
|
||||||
edfa.operational.gain_target = gain
|
edfa.operational.gain_target = gain
|
||||||
pref = Pref(0, -gain)
|
pref = Pref(0, -gain, lin2db(len(frequencies)))
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
result = edfa.nf
|
result = edfa.nf
|
||||||
assert pytest.approx(nf_expected, abs=0.01) == result[0]
|
assert pytest.approx(nf_expected, abs=0.01) == result[0]
|
||||||
@@ -93,7 +93,7 @@ def test_fixed_gain_nf(gain, nf_expected, setup_edfa_fixed_gain, si):
|
|||||||
pin = pin/db2lin(gain)
|
pin = pin/db2lin(gain)
|
||||||
baud_rates = array([c.baud_rate for c in si.carriers])
|
baud_rates = array([c.baud_rate for c in si.carriers])
|
||||||
edfa.operational.gain_target = gain
|
edfa.operational.gain_target = gain
|
||||||
pref = Pref(0, -gain)
|
pref = Pref(0, -gain, lin2db(len(frequencies)))
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
|
|
||||||
assert pytest.approx(nf_expected, abs=0.01) == edfa.nf[0]
|
assert pytest.approx(nf_expected, abs=0.01) == edfa.nf[0]
|
||||||
@@ -118,7 +118,7 @@ def test_compare_nf_models(gain, setup_edfa_variable_gain, si):
|
|||||||
pin = pin/db2lin(gain)
|
pin = pin/db2lin(gain)
|
||||||
baud_rates = array([c.baud_rate for c in si.carriers])
|
baud_rates = array([c.baud_rate for c in si.carriers])
|
||||||
edfa.operational.gain_target = gain
|
edfa.operational.gain_target = gain
|
||||||
pref = Pref(0, -gain)
|
pref = Pref(0, -gain, lin2db(len(frequencies)))
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
nf_model = edfa.nf[0]
|
nf_model = edfa.nf[0]
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
@@ -137,7 +137,7 @@ def test_ase_noise(gain, si, setup_edfa_variable_gain, setup_trx, bw):
|
|||||||
pin = array([c.power.signal+c.power.nli+c.power.ase for c in si.carriers])
|
pin = array([c.power.signal+c.power.nli+c.power.ase for c in si.carriers])
|
||||||
baud_rates = array([c.baud_rate for c in si.carriers])
|
baud_rates = array([c.baud_rate for c in si.carriers])
|
||||||
edfa.operational.gain_target = gain
|
edfa.operational.gain_target = gain
|
||||||
pref = Pref(0, 0)
|
pref = Pref(0, 0, lin2db(len(frequencies)))
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
nf = edfa.nf
|
nf = edfa.nf
|
||||||
pin = lin2db(pin[0]*1e3)
|
pin = lin2db(pin[0]*1e3)
|
||||||
|
|||||||
@@ -18,16 +18,14 @@ from pathlib import Path
|
|||||||
import pytest
|
import pytest
|
||||||
from gnpy.core.equipment import load_equipment, trx_mode_params, automatic_nch
|
from gnpy.core.equipment import load_equipment, trx_mode_params, automatic_nch
|
||||||
from gnpy.core.network import load_network, build_network
|
from gnpy.core.network import load_network, build_network
|
||||||
from examples.path_requests_run import (requests_from_json , correct_route_list ,
|
from examples.path_requests_run import requests_from_json, correct_route_list, load_requests
|
||||||
load_requests , disjunctions_from_json)
|
from gnpy.core.request import compute_path_dsjctn, propagate, propagate_and_optimize_mode
|
||||||
from gnpy.core.request import (compute_path_dsjctn, isdisjoint , find_reversed_path,
|
|
||||||
propagate,propagate_and_optimize_mode)
|
|
||||||
from gnpy.core.utils import db2lin, lin2db
|
from gnpy.core.utils import db2lin, lin2db
|
||||||
from gnpy.core.elements import Roadm
|
from gnpy.core.elements import Roadm
|
||||||
|
|
||||||
network_file_name = Path(__file__).parent.parent / 'tests/data/meshTopologyToy.json'
|
network_file_name = Path(__file__).parent.parent / 'tests/data/testTopology_expected.json'
|
||||||
service_file_name = Path(__file__).parent.parent / 'tests/data/meshTopologyToy_services.json'
|
service_file_name = Path(__file__).parent.parent / 'tests/data/testTopology_testservices.json'
|
||||||
result_file_name = Path(__file__).parent.parent / 'tests/data/meshTopologyToy_results.json'
|
result_file_name = Path(__file__).parent.parent / 'tests/data/testTopology_testresults.json'
|
||||||
eqpt_library_name = Path(__file__).parent.parent / 'tests/data/eqpt_config.json'
|
eqpt_library_name = Path(__file__).parent.parent / 'tests/data/eqpt_config.json'
|
||||||
|
|
||||||
@pytest.mark.parametrize("net",[network_file_name])
|
@pytest.mark.parametrize("net",[network_file_name])
|
||||||
@@ -35,7 +33,7 @@ eqpt_library_name = Path(__file__).parent.parent / 'tests/data/eqpt_config.json'
|
|||||||
@pytest.mark.parametrize("serv",[service_file_name])
|
@pytest.mark.parametrize("serv",[service_file_name])
|
||||||
@pytest.mark.parametrize("expected_mode",[['16QAM', 'PS_SP64_1', 'PS_SP64_1', 'PS_SP64_1', 'mode 2 - fake', 'mode 2', 'PS_SP64_1', 'mode 3', 'PS_SP64_1', 'PS_SP64_1', '16QAM', 'mode 1', 'PS_SP64_1', 'PS_SP64_1', 'mode 1', 'mode 2', 'mode 1', 'mode 2', 'nok']])
|
@pytest.mark.parametrize("expected_mode",[['16QAM', 'PS_SP64_1', 'PS_SP64_1', 'PS_SP64_1', 'mode 2 - fake', 'mode 2', 'PS_SP64_1', 'mode 3', 'PS_SP64_1', 'PS_SP64_1', '16QAM', 'mode 1', 'PS_SP64_1', 'PS_SP64_1', 'mode 1', 'mode 2', 'mode 1', 'mode 2', 'nok']])
|
||||||
def test_automaticmodefeature(net,eqpt,serv,expected_mode):
|
def test_automaticmodefeature(net,eqpt,serv,expected_mode):
|
||||||
data = load_requests(serv,eqpt)
|
data = load_requests(serv, eqpt, bidir=False)
|
||||||
equipment = load_equipment(eqpt)
|
equipment = load_equipment(eqpt)
|
||||||
network = load_network(net,equipment)
|
network = load_network(net,equipment)
|
||||||
|
|
||||||
@@ -72,7 +70,7 @@ def test_automaticmodefeature(net,eqpt,serv,expected_mode):
|
|||||||
if pathreq.baud_rate is not None:
|
if pathreq.baud_rate is not None:
|
||||||
print(pathreq.format)
|
print(pathreq.format)
|
||||||
path_res_list.append(pathreq.format)
|
path_res_list.append(pathreq.format)
|
||||||
total_path = propagate(total_path,pathreq,equipment, show=False)
|
total_path = propagate(total_path,pathreq,equipment)
|
||||||
else:
|
else:
|
||||||
total_path,mode = propagate_and_optimize_mode(total_path,pathreq,equipment)
|
total_path,mode = propagate_and_optimize_mode(total_path,pathreq,equipment)
|
||||||
# if no baudrate satisfies spacing, no mode is returned and an empty path is returned
|
# if no baudrate satisfies spacing, no mode is returned and an empty path is returned
|
||||||
|
|||||||
@@ -19,20 +19,20 @@ from examples.path_requests_run import (requests_from_json , correct_route_list
|
|||||||
from gnpy.core.request import compute_path_dsjctn, isdisjoint , find_reversed_path
|
from gnpy.core.request import compute_path_dsjctn, isdisjoint , find_reversed_path
|
||||||
from gnpy.core.utils import db2lin, lin2db
|
from gnpy.core.utils import db2lin, lin2db
|
||||||
from gnpy.core.elements import Roadm
|
from gnpy.core.elements import Roadm
|
||||||
|
from gnpy.core.spectrum_assignment import build_oms_list
|
||||||
|
|
||||||
network_file_name = Path(__file__).parent.parent / 'tests/data/meshTopologyToy.json'
|
network_file_name = Path(__file__).parent.parent / 'tests/data/testTopology_expected.json'
|
||||||
service_file_name = Path(__file__).parent.parent / 'tests/data/meshTopologyToy_services.json'
|
service_file_name = Path(__file__).parent.parent / 'tests/data/testTopology_testservices.json'
|
||||||
result_file_name = Path(__file__).parent.parent / 'tests/data/meshTopologyToy_results.json'
|
result_file_name = Path(__file__).parent.parent / 'tests/data/testTopology_testresults.json'
|
||||||
eqpt_library_name = Path(__file__).parent.parent / 'tests/data/eqpt_config.json'
|
eqpt_library_name = Path(__file__).parent.parent / 'tests/data/eqpt_config.json'
|
||||||
|
|
||||||
@pytest.mark.parametrize("net",[network_file_name])
|
@pytest.mark.parametrize("net",[network_file_name])
|
||||||
@pytest.mark.parametrize("eqpt", [eqpt_library_name])
|
@pytest.mark.parametrize("eqpt", [eqpt_library_name])
|
||||||
@pytest.mark.parametrize("serv",[service_file_name])
|
@pytest.mark.parametrize("serv",[service_file_name])
|
||||||
def test_disjunction(net,eqpt,serv):
|
def test_disjunction(net,eqpt,serv):
|
||||||
data = load_requests(serv,eqpt)
|
data = load_requests(serv, eqpt, bidir=False)
|
||||||
equipment = load_equipment(eqpt)
|
equipment = load_equipment(eqpt)
|
||||||
network = load_network(net,equipment)
|
network = load_network(net,equipment)
|
||||||
|
|
||||||
# Build the network once using the default power defined in SI in eqpt config
|
# Build the network once using the default power defined in SI in eqpt config
|
||||||
# power density : db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by
|
# power density : db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by
|
||||||
# spacing, f_min and f_max
|
# spacing, f_min and f_max
|
||||||
@@ -41,6 +41,7 @@ def test_disjunction(net,eqpt,serv):
|
|||||||
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||||
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||||
build_network(network, equipment, p_db, p_total_db)
|
build_network(network, equipment, p_db, p_total_db)
|
||||||
|
build_oms_list(network, equipment)
|
||||||
|
|
||||||
rqs = requests_from_json(data, equipment)
|
rqs = requests_from_json(data, equipment)
|
||||||
rqs = correct_route_list(network, rqs)
|
rqs = correct_route_list(network, rqs)
|
||||||
@@ -56,7 +57,7 @@ def test_disjunction(net,eqpt,serv):
|
|||||||
rqs_id_list = [r.request_id for r in rqs]
|
rqs_id_list = [r.request_id for r in rqs]
|
||||||
p1 = pths[rqs_id_list.index(e[0])][1:-1]
|
p1 = pths[rqs_id_list.index(e[0])][1:-1]
|
||||||
p2 = pths[rqs_id_list.index(e[1])][1:-1]
|
p2 = pths[rqs_id_list.index(e[1])][1:-1]
|
||||||
if isdisjoint(p1,p2) + isdisjoint(p1,find_reversed_path(p2, network)) > 0:
|
if isdisjoint(p1, p2) + isdisjoint(p1, find_reversed_path(p2)) > 0:
|
||||||
test = False
|
test = False
|
||||||
print(f'Computed path (roadms):{[e.uid for e in p1 if isinstance(e, Roadm)]}\n')
|
print(f'Computed path (roadms):{[e.uid for e in p1 if isinstance(e, Roadm)]}\n')
|
||||||
print(f'Computed path (roadms):{[e.uid for e in p2 if isinstance(e, Roadm)]}\n')
|
print(f'Computed path (roadms):{[e.uid for e in p2 if isinstance(e, Roadm)]}\n')
|
||||||
@@ -68,7 +69,7 @@ def test_disjunction(net,eqpt,serv):
|
|||||||
@pytest.mark.parametrize("eqpt", [eqpt_library_name])
|
@pytest.mark.parametrize("eqpt", [eqpt_library_name])
|
||||||
@pytest.mark.parametrize("serv",[service_file_name])
|
@pytest.mark.parametrize("serv",[service_file_name])
|
||||||
def test_does_not_loop_back(net,eqpt,serv):
|
def test_does_not_loop_back(net,eqpt,serv):
|
||||||
data = load_requests(serv,eqpt)
|
data = load_requests(serv, eqpt, bidir=False)
|
||||||
equipment = load_equipment(eqpt)
|
equipment = load_equipment(eqpt)
|
||||||
network = load_network(net,equipment)
|
network = load_network(net,equipment)
|
||||||
|
|
||||||
@@ -80,6 +81,7 @@ def test_does_not_loop_back(net,eqpt,serv):
|
|||||||
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||||
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||||
build_network(network, equipment, p_db, p_total_db)
|
build_network(network, equipment, p_db, p_total_db)
|
||||||
|
build_oms_list(network, equipment)
|
||||||
|
|
||||||
rqs = requests_from_json(data, equipment)
|
rqs = requests_from_json(data, equipment)
|
||||||
rqs = correct_route_list(network, rqs)
|
rqs = correct_route_list(network, rqs)
|
||||||
|
|||||||
@@ -3,43 +3,57 @@
|
|||||||
# @Author: Esther Le Rouzic
|
# @Author: Esther Le Rouzic
|
||||||
# @Date: 2018-06-15
|
# @Date: 2018-06-15
|
||||||
|
|
||||||
from gnpy.core.elements import Edfa
|
""" Adding tests to check the parser non regression
|
||||||
import numpy as np
|
convention of naming of test files:
|
||||||
|
- ..._expected.json for the reference output
|
||||||
|
tests:
|
||||||
|
- generation of topology json
|
||||||
|
- reading of Eqpt sheet w and W/ power mode
|
||||||
|
- consistency of autodesign
|
||||||
|
- generation of service list based on service sheet
|
||||||
|
- writing of results in csv
|
||||||
|
- writing of results in json (same keys)
|
||||||
|
"""
|
||||||
|
|
||||||
from json import load
|
from json import load
|
||||||
|
from pathlib import Path
|
||||||
|
from os import unlink
|
||||||
|
from pandas import read_csv
|
||||||
import pytest
|
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 tests.compare import compare_networks, compare_services
|
from tests.compare import compare_networks, compare_services
|
||||||
|
from copy import deepcopy
|
||||||
|
from gnpy.core.utils import lin2db
|
||||||
|
from gnpy.core.network import save_network, build_network
|
||||||
from gnpy.core.convert import convert_file
|
from gnpy.core.convert import convert_file
|
||||||
from gnpy.core.service_sheet import convert_service_sheet
|
from gnpy.core.service_sheet import convert_service_sheet
|
||||||
from pathlib import Path
|
from gnpy.core.equipment import load_equipment, automatic_nch
|
||||||
import filecmp
|
from gnpy.core.network import load_network
|
||||||
from os import unlink
|
from gnpy.core.request import (jsontocsv, requests_aggregation,
|
||||||
|
compute_path_dsjctn, Result_element)
|
||||||
|
from gnpy.core.spectrum_assignment import build_oms_list, pth_assign_spectrum
|
||||||
|
from gnpy.core.exceptions import ServiceError
|
||||||
|
from examples.path_requests_run import (requests_from_json, disjunctions_from_json,
|
||||||
|
correct_route_list, correct_disjn,
|
||||||
|
compute_path_with_disjunction)
|
||||||
|
|
||||||
TEST_DIR = Path(__file__).parent
|
TEST_DIR = Path(__file__).parent
|
||||||
DATA_DIR = TEST_DIR / 'data'
|
DATA_DIR = TEST_DIR / 'data'
|
||||||
eqpt_filename = DATA_DIR / 'eqpt_config.json'
|
eqpt_filename = DATA_DIR / 'eqpt_config.json'
|
||||||
|
|
||||||
# adding tests to check the parser non regression
|
|
||||||
# convention of naming of test files:
|
|
||||||
#
|
|
||||||
# - ..._expected.json for the reference output
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('xls_input,expected_json_output', {
|
@pytest.mark.parametrize('xls_input,expected_json_output', {
|
||||||
DATA_DIR / 'excelTestFile.xls': DATA_DIR / 'excelTestFile_expected.json',
|
|
||||||
DATA_DIR / 'CORONET_Global_Topology.xls': DATA_DIR / 'CORONET_Global_Topology_expected.json',
|
DATA_DIR / 'CORONET_Global_Topology.xls': DATA_DIR / 'CORONET_Global_Topology_expected.json',
|
||||||
DATA_DIR / 'meshTopologyExampleV2.xls': DATA_DIR / 'meshTopologyExampleV2_expected.json',
|
DATA_DIR / 'testTopology.xls': DATA_DIR / 'testTopology_expected.json',
|
||||||
DATA_DIR / 'meshTopologyExampleV2Eqpt.xls': DATA_DIR / 'meshTopologyExampleV2Eqpt_expected.json',
|
|
||||||
}.items())
|
}.items())
|
||||||
def test_excel_json_generation(xls_input, expected_json_output):
|
def test_excel_json_generation(xls_input, expected_json_output):
|
||||||
|
""" tests generation of topology json
|
||||||
|
"""
|
||||||
convert_file(xls_input)
|
convert_file(xls_input)
|
||||||
|
|
||||||
actual_json_output = xls_input.with_suffix('.json')
|
actual_json_output = xls_input.with_suffix('.json')
|
||||||
with open(actual_json_output, encoding='utf-8') as f:
|
with open(actual_json_output, encoding='utf-8') as f:
|
||||||
actual = load(f)
|
actual = load(f)
|
||||||
#unlink(actual_json_output)
|
unlink(actual_json_output)
|
||||||
|
|
||||||
with open(expected_json_output, encoding='utf-8') as f:
|
with open(expected_json_output, encoding='utf-8') as f:
|
||||||
expected = load(f)
|
expected = load(f)
|
||||||
@@ -52,16 +66,97 @@ def test_excel_json_generation(xls_input, expected_json_output):
|
|||||||
assert not results.connections.extra
|
assert not results.connections.extra
|
||||||
assert not results.connections.different
|
assert not results.connections.different
|
||||||
|
|
||||||
# assume json entries
|
# assume xls entries
|
||||||
# test that the build network gives correct results
|
# test that the build network gives correct results in gain mode
|
||||||
# TODO !!
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('xls_input,expected_json_output',
|
||||||
|
{DATA_DIR / 'CORONET_Global_Topology.xls':\
|
||||||
|
DATA_DIR / 'CORONET_Global_Topology_auto_design_expected.json',
|
||||||
|
DATA_DIR / 'testTopology.xls':\
|
||||||
|
DATA_DIR / 'testTopology_auto_design_expected.json',
|
||||||
|
}.items())
|
||||||
|
def test_auto_design_generation_fromxlsgainmode(xls_input, expected_json_output):
|
||||||
|
""" tests generation of topology json
|
||||||
|
test that the build network gives correct results in gain mode
|
||||||
|
"""
|
||||||
|
equipment = load_equipment(eqpt_filename)
|
||||||
|
network = load_network(xls_input, equipment)
|
||||||
|
# in order to test the Eqpt sheet and load gain target,
|
||||||
|
# change the power-mode to False (to be in gain mode)
|
||||||
|
equipment['Span']['default'].power_mode = False
|
||||||
|
# Build the network once using the default power defined in SI in eqpt config
|
||||||
|
|
||||||
|
p_db = equipment['SI']['default'].power_dbm
|
||||||
|
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||||
|
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||||
|
build_network(network, equipment, p_db, p_total_db)
|
||||||
|
save_network(xls_input, network)
|
||||||
|
|
||||||
|
actual_json_output = f'{str(xls_input)[0:len(str(xls_input))-4]}_auto_design.json'
|
||||||
|
|
||||||
|
with open(actual_json_output, encoding='utf-8') as f:
|
||||||
|
actual = load(f)
|
||||||
|
unlink(actual_json_output)
|
||||||
|
|
||||||
|
with open(expected_json_output, encoding='utf-8') as f:
|
||||||
|
expected = load(f)
|
||||||
|
|
||||||
|
results = compare_networks(expected, actual)
|
||||||
|
assert not results.elements.missing
|
||||||
|
assert not results.elements.extra
|
||||||
|
assert not results.elements.different
|
||||||
|
assert not results.connections.missing
|
||||||
|
assert not results.connections.extra
|
||||||
|
assert not results.connections.different
|
||||||
|
|
||||||
|
#test that autodesign creates same file as an input file already autodesigned
|
||||||
|
@pytest.mark.parametrize('json_input,expected_json_output',
|
||||||
|
{DATA_DIR / 'CORONET_Global_Topology_auto_design_expected.json':\
|
||||||
|
DATA_DIR / 'CORONET_Global_Topology_auto_design_expected.json',
|
||||||
|
DATA_DIR / 'testTopology_auto_design_expected.json':\
|
||||||
|
DATA_DIR / 'testTopology_auto_design_expected.json',
|
||||||
|
}.items())
|
||||||
|
def test_auto_design_generation_fromjson(json_input, expected_json_output):
|
||||||
|
"""test that autodesign creates same file as an input file already autodesigned
|
||||||
|
"""
|
||||||
|
equipment = load_equipment(eqpt_filename)
|
||||||
|
network = load_network(json_input, equipment)
|
||||||
|
# in order to test the Eqpt sheet and load gain target,
|
||||||
|
# change the power-mode to False (to be in gain mode)
|
||||||
|
equipment['Span']['default'].power_mode = False
|
||||||
|
# Build the network once using the default power defined in SI in eqpt config
|
||||||
|
|
||||||
|
p_db = equipment['SI']['default'].power_dbm
|
||||||
|
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||||
|
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||||
|
build_network(network, equipment, p_db, p_total_db)
|
||||||
|
save_network(json_input, network)
|
||||||
|
|
||||||
|
actual_json_output = f'{str(json_input)[0:len(str(json_input))-5]}_auto_design.json'
|
||||||
|
|
||||||
|
with open(actual_json_output, encoding='utf-8') as f:
|
||||||
|
actual = load(f)
|
||||||
|
unlink(actual_json_output)
|
||||||
|
|
||||||
|
with open(expected_json_output, encoding='utf-8') as f:
|
||||||
|
expected = load(f)
|
||||||
|
|
||||||
|
results = compare_networks(expected, actual)
|
||||||
|
assert not results.elements.missing
|
||||||
|
assert not results.elements.extra
|
||||||
|
assert not results.elements.different
|
||||||
|
assert not results.connections.missing
|
||||||
|
assert not results.connections.extra
|
||||||
|
assert not results.connections.different
|
||||||
|
|
||||||
|
# test services creation
|
||||||
@pytest.mark.parametrize('xls_input,expected_json_output', {
|
@pytest.mark.parametrize('xls_input,expected_json_output', {
|
||||||
DATA_DIR / 'excelTestFile.xls': DATA_DIR / 'excelTestFile_services_expected.json',
|
DATA_DIR / 'testTopology.xls': DATA_DIR / 'testTopology_services_expected.json',
|
||||||
DATA_DIR / 'meshTopologyExampleV2.xls': DATA_DIR / 'meshTopologyExampleV2_services_expected.json',
|
DATA_DIR / 'testService.xls': DATA_DIR / 'testService_services_expected.json'
|
||||||
DATA_DIR / 'meshTopologyExampleV2Eqpt.xls': DATA_DIR / 'meshTopologyExampleV2Eqpt_services_expected.json',
|
|
||||||
}.items())
|
}.items())
|
||||||
def test_excel_service_json_generation(xls_input, expected_json_output):
|
def test_excel_service_json_generation(xls_input, expected_json_output):
|
||||||
|
""" test services creation
|
||||||
|
"""
|
||||||
convert_service_sheet(xls_input, eqpt_filename)
|
convert_service_sheet(xls_input, eqpt_filename)
|
||||||
|
|
||||||
actual_json_output = f'{str(xls_input)[:-4]}_services.json'
|
actual_json_output = f'{str(xls_input)[:-4]}_services.json'
|
||||||
@@ -79,3 +174,173 @@ def test_excel_service_json_generation(xls_input, expected_json_output):
|
|||||||
assert not results.synchronizations.missing
|
assert not results.synchronizations.missing
|
||||||
assert not results.synchronizations.extra
|
assert not results.synchronizations.extra
|
||||||
assert not results.synchronizations.different
|
assert not results.synchronizations.different
|
||||||
|
|
||||||
|
# TODO verify that requested bandwidth is not zero !
|
||||||
|
|
||||||
|
# test xls answers creation
|
||||||
|
@pytest.mark.parametrize('json_input, csv_output', {
|
||||||
|
DATA_DIR / 'testTopology_response.json': DATA_DIR / 'testTopology_response',
|
||||||
|
}.items())
|
||||||
|
def test_csv_response_generation(json_input, csv_output):
|
||||||
|
""" tests if generated csv is consistant with expected generation
|
||||||
|
same columns (order not important)
|
||||||
|
"""
|
||||||
|
with open(json_input) as jsonfile:
|
||||||
|
json_data = load(jsonfile)
|
||||||
|
equipment = load_equipment(eqpt_filename)
|
||||||
|
csv_filename = str(csv_output)+'.csv'
|
||||||
|
with open(csv_filename, 'w', encoding='utf-8') as fcsv:
|
||||||
|
jsontocsv(json_data, equipment, fcsv)
|
||||||
|
|
||||||
|
expected_csv_filename = str(csv_output)+'_expected.csv'
|
||||||
|
|
||||||
|
# expected header
|
||||||
|
# csv_header = \
|
||||||
|
# [
|
||||||
|
# 'response-id',
|
||||||
|
# 'source',
|
||||||
|
# 'destination',
|
||||||
|
# 'path_bandwidth',
|
||||||
|
# 'Pass?',
|
||||||
|
# 'nb of tsp pairs',
|
||||||
|
# 'total cost',
|
||||||
|
# 'transponder-type',
|
||||||
|
# 'transponder-mode',
|
||||||
|
# 'OSNR-0.1nm',
|
||||||
|
# 'SNR-0.1nm',
|
||||||
|
# 'SNR-bandwidth',
|
||||||
|
# 'baud rate (Gbaud)',
|
||||||
|
# 'input power (dBm)',
|
||||||
|
# 'path',
|
||||||
|
# 'spectrum (N,M)',
|
||||||
|
# 'reversed path OSNR-0.1nm',
|
||||||
|
# 'reversed path SNR-0.1nm',
|
||||||
|
# 'reversed path SNR-bandwidth'
|
||||||
|
# ]
|
||||||
|
|
||||||
|
resp = read_csv(csv_filename)
|
||||||
|
print(resp)
|
||||||
|
unlink(csv_filename)
|
||||||
|
expected_resp = read_csv(expected_csv_filename)
|
||||||
|
print(expected_resp)
|
||||||
|
resp_header = list(resp.head(0))
|
||||||
|
expected_resp_header = list(expected_resp.head(0))
|
||||||
|
# check that headers are the same
|
||||||
|
resp_header.sort()
|
||||||
|
expected_resp_header.sort()
|
||||||
|
print('headers are differents')
|
||||||
|
print(resp_header)
|
||||||
|
print(expected_resp_header)
|
||||||
|
assert resp_header == expected_resp_header
|
||||||
|
|
||||||
|
# for each header checks that the output are as expected
|
||||||
|
resp.sort_values(by=['response-id'])
|
||||||
|
expected_resp.sort_values(by=['response-id'])
|
||||||
|
|
||||||
|
for column in expected_resp:
|
||||||
|
assert list(resp[column].fillna('')) == list(expected_resp[column].fillna(''))
|
||||||
|
print('results are different')
|
||||||
|
print(list(resp[column]))
|
||||||
|
print(list(expected_resp[column]))
|
||||||
|
print(type(list(resp[column])[-1]))
|
||||||
|
|
||||||
|
def compare_response(exp_resp, act_resp):
|
||||||
|
""" False if the keys are different in the nested dicts as well
|
||||||
|
"""
|
||||||
|
print(exp_resp)
|
||||||
|
print(act_resp)
|
||||||
|
test = True
|
||||||
|
for key in act_resp.keys():
|
||||||
|
if not key in exp_resp.keys():
|
||||||
|
print(f'{key} is not expected')
|
||||||
|
return False
|
||||||
|
if isinstance(act_resp[key], dict):
|
||||||
|
test = compare_response(exp_resp[key], act_resp[key])
|
||||||
|
if test:
|
||||||
|
for key in exp_resp.keys():
|
||||||
|
if not key in act_resp.keys():
|
||||||
|
print(f'{key} is expected')
|
||||||
|
return False
|
||||||
|
if isinstance(exp_resp[key], dict):
|
||||||
|
test = compare_response(exp_resp[key], act_resp[key])
|
||||||
|
|
||||||
|
# at this point exp_resp and act_resp have the same keys. Check if their values are the same
|
||||||
|
for key in act_resp.keys():
|
||||||
|
if not isinstance(act_resp[key], dict):
|
||||||
|
if exp_resp[key] != act_resp[key]:
|
||||||
|
print(f'expected value :{exp_resp[key]}\n actual value: {act_resp[key]}')
|
||||||
|
return False
|
||||||
|
return test
|
||||||
|
|
||||||
|
|
||||||
|
# test json answers creation
|
||||||
|
@pytest.mark.parametrize('xls_input, expected_response_file', {
|
||||||
|
DATA_DIR / 'testTopology.xls': DATA_DIR / 'testTopology_response.json',
|
||||||
|
}.items())
|
||||||
|
def test_json_response_generation(xls_input, expected_response_file):
|
||||||
|
""" tests if json response is correctly generated for all combinations of requests
|
||||||
|
"""
|
||||||
|
data = convert_service_sheet(xls_input, eqpt_filename)
|
||||||
|
# change one of the request with bidir option to cover bidir case as well
|
||||||
|
data['path-request'][2]['bidirectional'] = True
|
||||||
|
|
||||||
|
equipment = load_equipment(eqpt_filename)
|
||||||
|
network = load_network(xls_input, equipment)
|
||||||
|
p_db = equipment['SI']['default'].power_dbm
|
||||||
|
|
||||||
|
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||||
|
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||||
|
build_network(network, equipment, p_db, p_total_db)
|
||||||
|
oms_list = build_oms_list(network, equipment)
|
||||||
|
rqs = requests_from_json(data, equipment)
|
||||||
|
rqs = correct_route_list(network, rqs)
|
||||||
|
dsjn = disjunctions_from_json(data)
|
||||||
|
dsjn = correct_disjn(dsjn)
|
||||||
|
rqs, dsjn = requests_aggregation(rqs, dsjn)
|
||||||
|
pths = compute_path_dsjctn(network, equipment, rqs, dsjn)
|
||||||
|
propagatedpths, reversed_pths, reversed_propagatedpths = \
|
||||||
|
compute_path_with_disjunction(network, equipment, rqs, pths)
|
||||||
|
pth_assign_spectrum(pths, rqs, oms_list, reversed_pths)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for i, pth in enumerate(propagatedpths):
|
||||||
|
# test ServiceError handling : when M is zero at this point, the
|
||||||
|
# json result should not be created if there is no blocking reason
|
||||||
|
if i == 1:
|
||||||
|
my_rq = deepcopy(rqs[i])
|
||||||
|
my_rq.M = 0
|
||||||
|
with pytest.raises(ServiceError):
|
||||||
|
Result_element(my_rq, pth, reversed_propagatedpths[i]).json
|
||||||
|
|
||||||
|
my_rq.blocking_reason = 'NO_SPECTRUM'
|
||||||
|
Result_element(my_rq, pth, reversed_propagatedpths[i]).json
|
||||||
|
|
||||||
|
result.append(Result_element(rqs[i], pth, reversed_propagatedpths[i]))
|
||||||
|
|
||||||
|
temp = {
|
||||||
|
'response': [n.json for n in result]
|
||||||
|
}
|
||||||
|
# load expected result and compare keys and values
|
||||||
|
|
||||||
|
with open(expected_response_file) as jsonfile:
|
||||||
|
expected = load(jsonfile)
|
||||||
|
# since we changes bidir attribute of request#2, need to add the corresponding
|
||||||
|
# metric in response
|
||||||
|
|
||||||
|
for i, response in enumerate(temp['response']):
|
||||||
|
if i == 2:
|
||||||
|
# compare response must be False because z-a metric is missing
|
||||||
|
# (request with bidir option to cover bidir case)
|
||||||
|
assert not compare_response(expected['response'][i], response)
|
||||||
|
print(f'response {response["response-id"]} should not match')
|
||||||
|
expected['response'][2]['path-properties']['z-a-path-metric'] = [
|
||||||
|
{'metric-type': 'SNR-bandwidth', 'accumulative-value': 22.809999999999999},
|
||||||
|
{'metric-type': 'SNR-0.1nm', 'accumulative-value': 26.890000000000001},
|
||||||
|
{'metric-type': 'OSNR-bandwidth', 'accumulative-value': 26.239999999999998},
|
||||||
|
{'metric-type': 'OSNR-0.1nm', 'accumulative-value': 30.32},
|
||||||
|
{'metric-type': 'reference_power', 'accumulative-value': 0.0012589254117941673},
|
||||||
|
{'metric-type': 'path_bandwidth', 'accumulative-value': 60000000000.0}]
|
||||||
|
# test should be OK now
|
||||||
|
else:
|
||||||
|
assert compare_response(expected['response'][i], response)
|
||||||
|
print(f'response {response["response-id"]} is not correct')
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ from numpy import mean
|
|||||||
|
|
||||||
#network_file_name = 'tests/test_network.json'
|
#network_file_name = 'tests/test_network.json'
|
||||||
network_file_name = Path(__file__).parent.parent / 'tests/LinkforTest.json'
|
network_file_name = Path(__file__).parent.parent / 'tests/LinkforTest.json'
|
||||||
|
#TODO: note that this json entries has a weird topology since EDfa1 has a possible branch on a receiver B
|
||||||
|
# this might not pass future tests/ code updates
|
||||||
#network_file_name = Path(__file__).parent.parent / 'examples/edfa_example_network.json'
|
#network_file_name = Path(__file__).parent.parent / 'examples/edfa_example_network.json'
|
||||||
eqpt_library_name = Path(__file__).parent.parent / 'tests/data/eqpt_config.json'
|
eqpt_library_name = Path(__file__).parent.parent / 'tests/data/eqpt_config.json'
|
||||||
|
|
||||||
@@ -47,12 +49,8 @@ def propagation(input_power, con_in, con_out,dest):
|
|||||||
|
|
||||||
p = input_power
|
p = input_power
|
||||||
p = db2lin(p) * 1e-3
|
p = db2lin(p) * 1e-3
|
||||||
spacing = 0.05 # THz
|
spacing = 50e9 # THz
|
||||||
si = SpectralInformation() # SI units: W, Hz
|
si = create_input_spectral_information(191.3e12, 191.3e12+79*spacing, 0.15, 32e9, p, spacing)
|
||||||
si = si.update(carriers=[
|
|
||||||
Channel(f, (191.3 + spacing * f) * 1e12, 32e9, 0.15, Power(p, 0, 0))
|
|
||||||
for f in range(1,80)
|
|
||||||
])
|
|
||||||
source = next(transceivers[uid] for uid in transceivers if uid == 'trx A')
|
source = next(transceivers[uid] for uid in transceivers if uid == 'trx A')
|
||||||
sink = next(transceivers[uid] for uid in transceivers if uid == dest)
|
sink = next(transceivers[uid] for uid in transceivers if uid == dest)
|
||||||
path = dijkstra_path(network, source, sink)
|
path = dijkstra_path(network, source, sink)
|
||||||
|
|||||||
203
tests/test_roadm_restrictions.py
Normal file
203
tests/test_roadm_restrictions.py
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Author: Esther Le Rouzic
|
||||||
|
# @Date: 2019-05-22
|
||||||
|
"""
|
||||||
|
@author: esther.lerouzic
|
||||||
|
checks that fused placed in amp type is correctly converted to a fused element instead of an edfa
|
||||||
|
and that no additional amp is added.
|
||||||
|
checks that restrictions in roadms are correctly applied during autodesign
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import pytest
|
||||||
|
from gnpy.core.utils import lin2db, load_json
|
||||||
|
from gnpy.core.elements import Fused, Roadm, Edfa
|
||||||
|
from gnpy.core.equipment import load_equipment, Amp, automatic_nch
|
||||||
|
from gnpy.core.network import network_from_json, build_network
|
||||||
|
|
||||||
|
|
||||||
|
TEST_DIR = Path(__file__).parent
|
||||||
|
EQPT_LIBRARY_NAME = TEST_DIR / 'data/eqpt_config.json'
|
||||||
|
NETWORK_FILE_NAME = TEST_DIR / 'data/testTopology_expected.json'
|
||||||
|
# adding tests to check the roadm restrictions
|
||||||
|
|
||||||
|
# mark node_uid amps as fused for testing purpose
|
||||||
|
@pytest.mark.parametrize("node_uid", ['east edfa in Lannion_CAS to Stbrieuc'])
|
||||||
|
def test_no_amp_feature(node_uid):
|
||||||
|
''' Check that booster is not placed on a roadm if fused is specified
|
||||||
|
test_parser covers partly this behaviour. This test should guaranty that the
|
||||||
|
feature is preserved even if convert is changed
|
||||||
|
'''
|
||||||
|
equipment = load_equipment(EQPT_LIBRARY_NAME)
|
||||||
|
json_network = load_json(NETWORK_FILE_NAME)
|
||||||
|
|
||||||
|
for elem in json_network['elements']:
|
||||||
|
if elem['uid'] == node_uid:
|
||||||
|
#replace edfa node by a fused node in the topology
|
||||||
|
elem['type'] = 'Fused'
|
||||||
|
elem.pop('type_variety')
|
||||||
|
elem.pop('operational')
|
||||||
|
elem['params'] = {'loss': 0}
|
||||||
|
|
||||||
|
next_node_uid = next(conn['to_node'] for conn in json_network['connections'] \
|
||||||
|
if conn['from_node'] == node_uid)
|
||||||
|
previous_node_uid = next(conn['from_node'] for conn in json_network['connections'] \
|
||||||
|
if conn['to_node'] == node_uid)
|
||||||
|
|
||||||
|
network = network_from_json(json_network, equipment)
|
||||||
|
# Build the network once using the default power defined in SI in eqpt config
|
||||||
|
# power density : db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by
|
||||||
|
# spacing, f_min and f_max
|
||||||
|
p_db = equipment['SI']['default'].power_dbm
|
||||||
|
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||||
|
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||||
|
|
||||||
|
build_network(network, equipment, p_db, p_total_db)
|
||||||
|
|
||||||
|
node = next(nd for nd in network.nodes() if nd.uid == node_uid)
|
||||||
|
next_node = next(network.successors(node))
|
||||||
|
previous_node = next(network.predecessors(node))
|
||||||
|
|
||||||
|
if not isinstance(node, Fused):
|
||||||
|
raise AssertionError()
|
||||||
|
if not node.params.loss == 0.0:
|
||||||
|
raise AssertionError()
|
||||||
|
if not next_node_uid == next_node.uid:
|
||||||
|
raise AssertionError()
|
||||||
|
if not previous_node_uid == previous_node.uid:
|
||||||
|
raise AssertionError()
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def equipment():
|
||||||
|
"""init transceiver class to access snr and osnr calculations"""
|
||||||
|
equipment = load_equipment(EQPT_LIBRARY_NAME)
|
||||||
|
# define some booster and preamps
|
||||||
|
restrictions_list = [
|
||||||
|
{
|
||||||
|
'type_variety': 'booster_medium_gain',
|
||||||
|
'type_def': 'variable_gain',
|
||||||
|
'gain_flatmax': 25,
|
||||||
|
'gain_min': 15,
|
||||||
|
'p_max': 21,
|
||||||
|
'nf_min': 5.8,
|
||||||
|
'nf_max': 10,
|
||||||
|
'out_voa_auto': False,
|
||||||
|
'allowed_for_design': False
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'type_variety': 'preamp_medium_gain',
|
||||||
|
'type_def': 'variable_gain',
|
||||||
|
'gain_flatmax': 26,
|
||||||
|
'gain_min': 15,
|
||||||
|
'p_max': 23,
|
||||||
|
'nf_min': 6,
|
||||||
|
'nf_max': 10,
|
||||||
|
'out_voa_auto': False,
|
||||||
|
'allowed_for_design': False
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'type_variety': 'preamp_high_gain',
|
||||||
|
'type_def': 'variable_gain',
|
||||||
|
'gain_flatmax': 35,
|
||||||
|
'gain_min': 25,
|
||||||
|
'p_max': 21,
|
||||||
|
'nf_min': 5.5,
|
||||||
|
'nf_max': 7,
|
||||||
|
'out_voa_auto': False,
|
||||||
|
'allowed_for_design': False
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'type_variety': 'preamp_low_gain',
|
||||||
|
'type_def': 'variable_gain',
|
||||||
|
'gain_flatmax': 16,
|
||||||
|
'gain_min': 8,
|
||||||
|
'p_max': 23,
|
||||||
|
'nf_min': 6.5,
|
||||||
|
'nf_max': 11,
|
||||||
|
'out_voa_auto': False,
|
||||||
|
'allowed_for_design': False
|
||||||
|
}]
|
||||||
|
# add them to the library
|
||||||
|
for entry in restrictions_list:
|
||||||
|
equipment['Edfa'][entry['type_variety']] = Amp.from_json(EQPT_LIBRARY_NAME, **entry)
|
||||||
|
return equipment
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("restrictions", [
|
||||||
|
{
|
||||||
|
'preamp_variety_list':[],
|
||||||
|
'booster_variety_list':[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'preamp_variety_list':[],
|
||||||
|
'booster_variety_list':['booster_medium_gain']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'preamp_variety_list':['preamp_medium_gain', 'preamp_high_gain', 'preamp_low_gain'],
|
||||||
|
'booster_variety_list':[]
|
||||||
|
}])
|
||||||
|
def test_restrictions(restrictions, equipment):
|
||||||
|
''' test that restriction is correctly applied if provided in eqpt_config and if no Edfa type
|
||||||
|
were provided in the network json
|
||||||
|
'''
|
||||||
|
# add restrictions
|
||||||
|
equipment['Roadm']['default'].restrictions = restrictions
|
||||||
|
# build network
|
||||||
|
json_network = load_json(NETWORK_FILE_NAME)
|
||||||
|
network = network_from_json(json_network, equipment)
|
||||||
|
|
||||||
|
amp_nodes_nobuild_uid = [nd.uid for nd in network.nodes() \
|
||||||
|
if isinstance(nd, Edfa) and isinstance(next(network.predecessors(nd)), Roadm)]
|
||||||
|
preamp_nodes_nobuild_uid = [nd.uid for nd in network.nodes() \
|
||||||
|
if isinstance(nd, Edfa) and isinstance(next(network.successors(nd)), Roadm)]
|
||||||
|
amp_nodes_nobuild = {nd.uid : nd for nd in network.nodes() \
|
||||||
|
if isinstance(nd, Edfa) and isinstance(next(network.predecessors(nd)), Roadm)}
|
||||||
|
preamp_nodes_nobuild = {nd.uid : nd for nd in network.nodes() \
|
||||||
|
if isinstance(nd, Edfa) and isinstance(next(network.successors(nd)), Roadm)}
|
||||||
|
# roadm dict with restrictions before build
|
||||||
|
roadms = {nd.uid: nd for nd in network.nodes() if isinstance(nd, Roadm)}
|
||||||
|
# Build the network once using the default power defined in SI in eqpt config
|
||||||
|
# power density : db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by
|
||||||
|
# spacing, f_min and f_max
|
||||||
|
p_db = equipment['SI']['default'].power_dbm
|
||||||
|
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||||
|
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||||
|
|
||||||
|
build_network(network, equipment, p_db, p_total_db)
|
||||||
|
|
||||||
|
amp_nodes = [nd for nd in network.nodes() \
|
||||||
|
if isinstance(nd, Edfa) and isinstance(next(network.predecessors(nd)), Roadm)\
|
||||||
|
and next(network.predecessors(nd)).restrictions['booster_variety_list']]
|
||||||
|
|
||||||
|
preamp_nodes = [nd for nd in network.nodes() \
|
||||||
|
if isinstance(nd, Edfa) and isinstance(next(network.successors(nd)), Roadm)\
|
||||||
|
and next(network.successors(nd)).restrictions['preamp_variety_list']]
|
||||||
|
|
||||||
|
# check that previously existing amp are not changed
|
||||||
|
for amp in amp_nodes:
|
||||||
|
if amp.uid in amp_nodes_nobuild_uid:
|
||||||
|
print(amp.uid, amp.params.type_variety)
|
||||||
|
if not amp.params.type_variety == amp_nodes_nobuild[amp.uid].params.type_variety:
|
||||||
|
raise AssertionError()
|
||||||
|
for amp in preamp_nodes:
|
||||||
|
if amp.uid in preamp_nodes_nobuild_uid:
|
||||||
|
if not amp.params.type_variety == preamp_nodes_nobuild[amp.uid].params.type_variety:
|
||||||
|
raise AssertionError()
|
||||||
|
# check that restrictions are correctly applied
|
||||||
|
for amp in amp_nodes:
|
||||||
|
if amp.uid not in amp_nodes_nobuild_uid:
|
||||||
|
# and if roadm had no restrictions before build:
|
||||||
|
if restrictions['booster_variety_list'] and \
|
||||||
|
not roadms[next(network.predecessors(amp)).uid]\
|
||||||
|
.restrictions['booster_variety_list']:
|
||||||
|
if not amp.params.type_variety in restrictions['booster_variety_list']:
|
||||||
|
|
||||||
|
raise AssertionError()
|
||||||
|
for amp in preamp_nodes:
|
||||||
|
if amp.uid not in preamp_nodes_nobuild_uid:
|
||||||
|
if restrictions['preamp_variety_list'] and\
|
||||||
|
not roadms[next(network.successors(amp)).uid].restrictions['preamp_variety_list']:
|
||||||
|
if not amp.params.type_variety in restrictions['preamp_variety_list']:
|
||||||
|
raise AssertionError()
|
||||||
49
tests/test_science_utils.py
Normal file
49
tests/test_science_utils.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Author: Alessio Ferrari
|
||||||
|
"""
|
||||||
|
checks that RamanFiber propagates properly the spectral information. In this way, also the RamanSolver and the NliSolver
|
||||||
|
are tested.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from pandas import read_csv
|
||||||
|
from numpy.testing import assert_allclose
|
||||||
|
from gnpy.core.info import create_input_spectral_information
|
||||||
|
from gnpy.core.elements import RamanFiber
|
||||||
|
from gnpy.core.network import load_sim_params
|
||||||
|
from pathlib import Path
|
||||||
|
TEST_DIR = Path(__file__).parent
|
||||||
|
|
||||||
|
def test_raman_fiber():
|
||||||
|
""" Test the accuracy of propagating the RamanFiber.
|
||||||
|
"""
|
||||||
|
# spectral information generation
|
||||||
|
power = 1e-3
|
||||||
|
with open(TEST_DIR / 'data' / 'eqpt_config.json', 'r') as file:
|
||||||
|
eqpt_params = json.load(file)
|
||||||
|
spectral_info_params = eqpt_params['SI'][0]
|
||||||
|
spectral_info_params.pop('power_dbm')
|
||||||
|
spectral_info_params.pop('power_range_db')
|
||||||
|
spectral_info_params.pop('tx_osnr')
|
||||||
|
spectral_info_params.pop('sys_margins')
|
||||||
|
spectral_info_input = create_input_spectral_information(power=power, **spectral_info_params)
|
||||||
|
|
||||||
|
# RamanFiber
|
||||||
|
with open(TEST_DIR / 'data' / 'raman_fiber_config.json', 'r') as file:
|
||||||
|
raman_fiber_params = json.load(file)
|
||||||
|
sim_params = load_sim_params(TEST_DIR / 'data' / 'sim_params.json')
|
||||||
|
fiber = RamanFiber(**raman_fiber_params)
|
||||||
|
fiber.sim_params = sim_params
|
||||||
|
|
||||||
|
# propagation
|
||||||
|
spectral_info_out = fiber(spectral_info_input)
|
||||||
|
|
||||||
|
p_signal = [carrier.power.signal for carrier in spectral_info_out.carriers]
|
||||||
|
p_ase = [carrier.power.ase for carrier in spectral_info_out.carriers]
|
||||||
|
p_nli = [carrier.power.nli for carrier in spectral_info_out.carriers]
|
||||||
|
|
||||||
|
expected_results = read_csv(TEST_DIR / 'data' / 'expected_results_science_utils.csv')
|
||||||
|
assert_allclose(p_signal, expected_results['signal'], rtol=1e-3)
|
||||||
|
assert_allclose(p_ase, expected_results['ase'], rtol=1e-3)
|
||||||
|
assert_allclose(p_nli, expected_results['nli'], rtol=1e-3)
|
||||||
Reference in New Issue
Block a user