mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-29 01:02:32 +00:00
Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c744a97d83 | ||
|
|
09221504d7 | ||
|
|
f2039fbe1c | ||
|
|
78227e65da | ||
|
|
e27e6d5c7b | ||
|
|
e3445e1066 | ||
|
|
a0758d0da5 | ||
|
|
0bc1fb3bf8 | ||
|
|
cd9d4c55b2 | ||
|
|
62889bf6af | ||
|
|
61787d5052 | ||
|
|
6612a46a9e | ||
|
|
f30515ba9d | ||
|
|
6f9897fe40 | ||
|
|
56e615c713 | ||
|
|
f447c908bc | ||
|
|
4df6cc6b23 | ||
|
|
6c5d11d86c | ||
|
|
1a795639c7 | ||
|
|
ee5e6f9b9e | ||
|
|
ea4ab1d61b | ||
|
|
d43fee5945 | ||
|
|
6603a50e78 | ||
|
|
b76c529c0c | ||
|
|
7a1b15a916 | ||
|
|
7bc9461547 | ||
|
|
b0ac41e2d5 | ||
|
|
bce42331c4 | ||
|
|
d5491c9ace | ||
|
|
689c2fb038 | ||
|
|
15c912bd72 | ||
|
|
d0c10e8537 | ||
|
|
93186b26fb | ||
|
|
49aee5a4e8 | ||
|
|
1c4da4794d | ||
|
|
de42dd4a93 | ||
|
|
57a5e9732b | ||
|
|
101eb8f969 | ||
|
|
7ce6650109 | ||
|
|
252e67a71e | ||
|
|
f83869392b | ||
|
|
94a3714aba | ||
|
|
ccab4835fc | ||
|
|
e55f7a5d4c | ||
|
|
4fda8c6002 | ||
|
|
8717156712 | ||
|
|
d2c0836164 | ||
|
|
eac4ba80ea | ||
|
|
4ef01d54a5 | ||
|
|
4b50ee0c2d | ||
|
|
33a289e22b | ||
|
|
e593b8c9ec | ||
|
|
94a6f922cd | ||
|
|
fbe387915b | ||
|
|
fce9d1d293 | ||
|
|
a59db8fd12 | ||
|
|
de509139b3 | ||
|
|
bb77b3f4a8 | ||
|
|
34c7fd1b60 | ||
|
|
89a962ffaf | ||
|
|
1722fbec13 | ||
|
|
e48aa57c35 | ||
|
|
e3e37b1986 | ||
|
|
abf42afaf8 | ||
|
|
310995045e | ||
|
|
c840bb1a44 | ||
|
|
4b6f4af3a5 | ||
|
|
dc68d38293 | ||
|
|
defe3bee5c | ||
|
|
32adc0fc53 | ||
|
|
4796266657 | ||
|
|
c35104c184 | ||
|
|
7b1354ee24 | ||
|
|
39d3f0f483 | ||
|
|
bbe9ef7356 | ||
|
|
42a8f018cd | ||
|
|
29f5dd1dc4 | ||
|
|
03da959724 | ||
|
|
f621ca6fe7 | ||
|
|
24f4503020 | ||
|
|
520c3615e4 | ||
|
|
548626a9f2 | ||
|
|
7a26833a5a | ||
|
|
c2f6f9c6a0 | ||
|
|
64a91256fc | ||
|
|
bdcffc2a5e | ||
|
|
c384af8062 | ||
|
|
0813332adc | ||
|
|
22fe9ead55 | ||
|
|
920ac30aa5 | ||
|
|
ac8fd770ab | ||
|
|
5277ae2005 | ||
|
|
30ead40e76 | ||
|
|
ae858b911a |
8
.github/workflows/main.yml
vendored
8
.github/workflows/main.yml
vendored
@@ -112,16 +112,18 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2019
|
||||
python_version: "3.10"
|
||||
- os: windows-2022
|
||||
python_version: "3.11"
|
||||
- os: windows-2022
|
||||
python_version: "3.12"
|
||||
- os: macos-12
|
||||
- os: windows-2025
|
||||
python_version: "3.11"
|
||||
- os: windows-2025
|
||||
python_version: "3.12"
|
||||
- os: macos-13
|
||||
python_version: "3.12"
|
||||
- os: macos-14
|
||||
python_version: "3.12"
|
||||
|
||||
paywalled-platforms:
|
||||
name: Tests on paywalled platforms
|
||||
|
||||
@@ -7,24 +7,29 @@ To learn how to contribute, please see CONTRIBUTING.md
|
||||
|
||||
- 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>
|
||||
- Andrea D'Amico (NEC) <adamico@nec-labs.com>
|
||||
- Arturo Mayoral (Telecom Infra Project) <amayoral@telecominfraproject.com>
|
||||
- Brian Taylor (Facebook) <briantaylor@fb.com>
|
||||
- David Boertjes (Ciena) <dboertje@ciena.com>
|
||||
- Diego Landa (Facebook) <dlanda@fb.com>
|
||||
- Emmanuelle Delfour (Orange) <WEDE7391@orange.com>
|
||||
- Esther Le Rouzic (Orange) <esther.lerouzic@orange.com>
|
||||
- Florian Frank (Orange) <florian1.frank@orange.com>
|
||||
- Gabriele Galimberti (Cisco) <ggalimbe@cisco.com>
|
||||
- Gert Grammel (Juniper Networks) <ggrammel@juniper.net>
|
||||
- Giacomo Borraccini (Politecnico di Torino) <giacomo.borraccini@polito.it>
|
||||
- Giacomo Borraccini (NEC Laboratories America) <gborraccini@nec-labs.com>
|
||||
- Gilad Goldfarb (Facebook) <giladg@fb.com>
|
||||
- James Powell (Telecom Infra Project) <james.powell@telecominfraproject.com>
|
||||
- Jan Kundrát (Telecom Infra Project) <jkt@jankundrat.com>
|
||||
- Jeanluc Augé (Orange) <jeanluc.auge@orange.com>
|
||||
- Jenny L'Escop (Orange) <jenny.lescop@orange.com>
|
||||
- Jonas Mårtensson (RISE) <jonas.martensson@ri.se>
|
||||
- Mattia Cantono (Politecnico di Torino) <mattia.cantono@polito.it>
|
||||
- Miguel Garrich (University Catalunya) <miquel.garrich@upct.es>
|
||||
- Raj Nagarajan (Lumentum) <raj.nagarajan@lumentum.com>
|
||||
- Renato Ambrosone (Politecnico di Torino) <renato.ambrosone@polito.it>
|
||||
- Roberts Miculens (Lattelecom) <roberts.miculens@lattelecom.lv>
|
||||
- Rodrigo Sasse David (Orange) <rodrigo.sassedavid@orange.com>
|
||||
- Sami Alavi (NUST) <sami.mansooralavi1999@gmail.com>
|
||||
- Shengxiang Zhu (University of Arizona) <szhu@email.arizona.edu>
|
||||
- Stefan Melin (Telia Company) <Stefan.Melin@teliacompany.com>
|
||||
|
||||
@@ -29,3 +29,7 @@ GNPy can do much more, including acting as a Path Computation Engine, tracking b
|
||||
Learn more about this [in the documentation](https://gnpy.readthedocs.io/), or give it a [try online at `gnpy.app`](https://gnpy.app/):
|
||||
|
||||
[](https://gnpy.app/)
|
||||
|
||||
## Project Calendar
|
||||
|
||||
See upcoming meetings on the [Project Calendar](https://telecominfraproject.github.io/oopt-gnpy/calendar.html). The calendar is embedded from Google Calendar and updates automatically.
|
||||
|
||||
4
docs/_static/custom.css
vendored
Normal file
4
docs/_static/custom.css
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
.wy-table-responsive table td, .wy-table-responsive table th {
|
||||
white-space: normal;
|
||||
}
|
||||
@@ -12,7 +12,8 @@ We encourage all interested people outside the TIP to [join the project](https:/
|
||||
|
||||
`gnpy` is looking for additional contributors, especially those with experience planning and maintaining large-scale, real-world mesh optical networks.
|
||||
|
||||
To get involved, please contact [Jan Kundrát](mailto:jkt@jankundrat.com) or [Gert Grammel](mailto:ggrammel@juniper.net).
|
||||
To get involved, please contact [Esther Le Rouzic](mailto:esther.lerouzic@orange.com) or
|
||||
[Andrea d'Amico](mailto:adamico@nec-labs.com) or [Gert Grammel](mailto:ggrammel@juniper.net).
|
||||
|
||||
`gnpy` contributions are currently limited to members of [TIP](http://telecominfraproject.com).
|
||||
Membership is free and open to all.
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
*********************************************
|
||||
Amplifier models and configuration
|
||||
*********************************************
|
||||
.. _amp_models:
|
||||
|
||||
**********************************
|
||||
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.
|
||||
It takes place in the equipment library such as **eqpt_config.json** file defined in example-data folder.
|
||||
By default **gnpy-transmission-example** 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.
|
||||
|
||||
@@ -28,9 +30,16 @@ Several amplifiers can be used by GNpy, so they are defined as an array of equip
|
||||
- *"variable_gain"*
|
||||
- *"fixed_gain"*
|
||||
- *"dual_stage"*
|
||||
- *"multi_band"*
|
||||
- *"openroadm"*
|
||||
*see next section for a full description of these models*
|
||||
|
||||
|
||||
- *"default_config_from_json"*:
|
||||
Use a custom per frequency dynamic gain tilt, gain and noise ripple arrays defined in the file specified with
|
||||
this option, instead of the default values from GNPy.
|
||||
|
||||
|
||||
- *"advanced_config_from_json"*:
|
||||
**This parameter is only applicable to the _"advanced_model"_ model**
|
||||
|
||||
@@ -135,7 +144,7 @@ Several amplifiers can be used by GNpy, so they are defined as an array of equip
|
||||
|
||||
|
||||
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.
|
||||
|
||||
@@ -179,7 +188,7 @@ In an opensource and multi-vendor environnement, it is needed to support differe
|
||||
- *"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.
|
||||
There is a default configuration to enforce 0 tilt and ripple values because GNPy core algorithm is a multi-carrier propagation.
|
||||
- gain_ripple =[0,...,0]
|
||||
- nf_ripple = [0,...,0]
|
||||
- dgt = [...] generic dgt comb
|
||||
@@ -250,7 +259,7 @@ In an opensource and multi-vendor environnement, it is needed to support differe
|
||||
|
||||
- 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.
|
||||
But unlike other models the 1st stage input will not be padded: it is always operated to its maximum gain and min NF. Therefore if gain adaptation and padding is needed it will be performed by the 2nd stage.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@@ -263,8 +272,18 @@ In an opensource and multi-vendor environnement, it is needed to support differe
|
||||
"allowed_for_design": true
|
||||
}
|
||||
|
||||
|
||||
- *"multiband"*
|
||||
This model enables the definition of multiband amplifiers that consist of multiple single-band
|
||||
amplifier elements, with each amplifier responsible for amplifying a different portion of the spectrum.
|
||||
The types of single-band amplifiers that can be included in these multiband amplifiers are specified,
|
||||
allowing for multiple options to be available for the same spectrum band (for instance, providing
|
||||
several permitted type varieties for both the C-band and the L-band). The actual element utilizing the
|
||||
type_variety must implement only one option for each band.
|
||||
|
||||
|
||||
4. advanced_config_from_json
|
||||
#######################################
|
||||
============================
|
||||
|
||||
The build_oa_json.py library in ``gnpy/example-data/edfa_model/`` can be used to build the json file required for the amplifier advanced_model type_def:
|
||||
|
||||
@@ -297,4 +316,3 @@ the json input file should have the following fields:
|
||||
"gain_ripple": "DFG_filename.txt",
|
||||
"dgt": "DGT_filename.txt"
|
||||
}
|
||||
|
||||
162
docs/biblio.bib
162
docs/biblio.bib
@@ -1860,3 +1860,165 @@ month={Sept},}
|
||||
pages={3499-3511},
|
||||
doi={10.1109/JLT.2022.3162134}
|
||||
}
|
||||
|
||||
@inproceedings{grammel2018physical,
|
||||
title={Physical simulation environment of the telecommunications infrastructure project (TIP)},
|
||||
author={Grammel, Gert and Curri, Vittorio and Auge, Jean-Luc},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={M1D--3},
|
||||
year={2018},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{taylor2018towards,
|
||||
title={Towards a route planning tool for open optical networks in the telecom infrastructure project},
|
||||
author={Taylor, Brian D and Goldfarb, Gilad and Bandyopadhyay, Saumil and Curri, Vittorio and Schmidtke, Hans-Juergen},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={Tu3E--4},
|
||||
year={2018},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@article{filer2018multi,
|
||||
title={Multi-vendor experimental validation of an open source QoT estimator for optical networks},
|
||||
author={Filer, Mark and Cantono, Mattia and Ferrari, Alessio and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
journal={Journal of Lightwave Technology},
|
||||
volume={36},
|
||||
number={15},
|
||||
pages={3073--3082},
|
||||
year={2018},
|
||||
publisher={IEEE}
|
||||
}
|
||||
|
||||
@inproceedings{auge2019open,
|
||||
title={Open optical network planning demonstration},
|
||||
author={Auge, Jean-Luc and Grammel, Gert and Le Rouzic, Esther and Curri, Vittorio and Galimberti, Gabriele and Powell, James},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={M3Z--9},
|
||||
year={2019},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{kundrat2020physical,
|
||||
title={Physical-layer awareness: GNPy and ONOS for end-to-end circuits in disaggregated networks},
|
||||
author={Kundr{\'a}t, Jan and Campanella, Andrea and Le Rouzic, Esther and Ferrari, Alessio and Havli{\v{s}}, Ond{\v{r}}ej and Ha{\v{z}}linsk{\`y}, Michal and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
booktitle={2020 Optical Fiber Communications Conference and Exhibition (OFC)},
|
||||
pages={1--3},
|
||||
year={2020},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
@inproceedings{ferrari2020experimental,
|
||||
title={Experimental validation of an open source quality of transmission estimator for open optical networks},
|
||||
author={Ferrari, Alessio and Filer, Mark and Balasubramanian, Karthikeyan and Yin, Yawei and Le Rouzic, Esther and Kundr{\'a}t, Jan and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
booktitle={2020 Optical Fiber Communications Conference and Exhibition (OFC)},
|
||||
pages={1--3},
|
||||
year={2020},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
@article{ferrari2020gnpy,
|
||||
title={GNPy: an open source application for physical layer aware open optical networks},
|
||||
author={Ferrari, Alessio and Filer, Mark and Balasubramanian, Karthikeyan and Yin, Yawei and Le Rouzic, Esther and Kundr{\'a}t, Jan and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
journal={Journal of Optical Communications and Networking},
|
||||
volume={12},
|
||||
number={6},
|
||||
pages={C31--C40},
|
||||
year={2020},
|
||||
publisher={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{ferrari2020softwarized,
|
||||
title={Softwarized optical transport QoT in production optical network: a Brownfield validation},
|
||||
author={Ferrari, Alessio and Balasubramanian, Karthikeyan and Filer, Mark and Yin, Yawei and Le Rouzic, Esther and Kundr{\'a}t, Jan and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
booktitle={2020 European Conference on Optical Communications (ECOC)},
|
||||
pages={1--4},
|
||||
year={2020},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
@article{ferrari2021assessment,
|
||||
title={Assessment on the in-field lightpath QoT computation including connector loss uncertainties},
|
||||
author={Ferrari, Alessio and Balasubramanian, Karthikeyan and Filer, Mark and Yin, Yawei and Le Rouzic, Esther and Kundr{\'a}t, Jan and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
journal={Journal of Optical Communications and Networking},
|
||||
volume={13},
|
||||
number={2},
|
||||
pages={A156--A164},
|
||||
year={2021},
|
||||
publisher={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{kundrat2021gnpy,
|
||||
title={GNPy \& YANG: open APIs for end-to-end service provisioning in optical networks},
|
||||
author={Kundr{\'a}t, Jan and Le Rouzic, Esther and M{\aa}rtensson, Jonas and Campanella, Andrea and Havli{\v{s}}, Ond{\v{r}}ej and D’Amico, Andrea and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio and Vojt{\v{e}}ch, Josef},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={M1B--6},
|
||||
year={2021},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{d2021gnpy,
|
||||
title={GNPy experimental validation on flex-grid, flex-rate WDM optical transport scenarios},
|
||||
author={D’Amico, Andrea and London, Elliot and Le Guyader, Bertrand and Frank, Florian and Le Rouzic, Esther and Pincemin, Erwan and Brochier, Nicolas and Curri, Vittorio},
|
||||
booktitle={Optical fiber communication conference},
|
||||
pages={W1G--2},
|
||||
year={2021},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{virgillito2021testing,
|
||||
title={Testing TIP open source solutions in deployed optical networks},
|
||||
author={Virgillito, Emanuele and Braun, Ralf-Peter and Breuer, Dirk and Gladisch, Andreas and Curri, Vittorio and Grammel, Gert},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={F1C--3},
|
||||
year={2021},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@article{d2022experimental,
|
||||
title={Experimental validation of GNPy in a multi-vendor flex-grid flex-rate WDM optical transport scenario},
|
||||
author={D’Amico, Andrea and London, Elliot and Le Guyader, Bertrand and Frank, Florian and Le Rouzic, Esther and Pincemin, Erwan and Brochier, Nicolas and Curri, Vittorio},
|
||||
journal={Journal of Optical Communications and Networking},
|
||||
volume={14},
|
||||
number={3},
|
||||
pages={79--88},
|
||||
year={2022},
|
||||
publisher={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{mano2022accuracy,
|
||||
title={Accuracy of nonlinear interference estimation on launch power optimization in short-reach systems with field trial},
|
||||
author={Mano, Toru and D’Amico, Andrea and Virgillito, Emanuele and Borraccini, Giacomo and Huang, Yue-Kai and Kitamura, Kei and Anazawa, Kazuya and Masuda, Akira and Nishizawa, Hideki and Wang, Ting and others},
|
||||
booktitle={European Conference and Exhibition on Optical Communication},
|
||||
pages={We3B--1},
|
||||
year={2022},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{kundrat2022gnpy,
|
||||
title={GNPy: Lessons learned and future plans},
|
||||
author={Kundr{\'a}t, Jan and Le Rouzic, Esther and M{\aa}rtensson, Jonas and Melin, Stefan and D’Amico, Andrea and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
booktitle={European Conference and Exhibition on Optical Communication},
|
||||
pages={We3B--6},
|
||||
year={2022},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{grammel2023open,
|
||||
title={Open Optical Networks: the good, the bad and the ugly},
|
||||
author={Grammel, Gert and Kundrat, Jan and Le Rouzic, Esther and Melin, Stefan and Curri, Vittorio and d'Amico, Andrea and Manzotti, Roberto},
|
||||
booktitle={49th European Conference on Optical Communications (ECOC 2023)},
|
||||
volume={2023},
|
||||
pages={1585--1588},
|
||||
year={2023},
|
||||
organization={IET}
|
||||
}
|
||||
|
||||
@inproceedings{d2024gnpy,
|
||||
title={GNPy Experimental Validation in a C+ L Multiband Optical Multiplex Section},
|
||||
author={D’Amico, Andrea and Gatto, Vittorio and Nespola, Antonino and Borraccini, Giacomo and Jiang, Yanchao and Poggiolini, Pierluigi and Le Rouzic, Esther and de Lerma, Arturo Mayoral L{\'o}pez and Grammel, Gert and Manzotti, Roberto and others},
|
||||
booktitle={2024 24th International Conference on Transparent Optical Networks (ICTON)},
|
||||
pages={1--4},
|
||||
year={2024},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
29
docs/calendar.html
Normal file
29
docs/calendar.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Project Calendar</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; margin: 20px; }
|
||||
.container { max-width: 1000px; margin: 0 auto; }
|
||||
h1 { font-size: 1.8rem; margin-bottom: 1rem; }
|
||||
iframe { border: 0; width: 100%; height: 800px; }
|
||||
.note { color: #555; margin-top: 1rem; font-size: 0.9rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Project Calendar</h1>
|
||||
<p>This page embeds the public project calendar. It updates automatically when events change in Google Calendar.</p>
|
||||
<iframe
|
||||
src="https://calendar.google.com/calendar/embed?src=c_0895d13d880537c3e54db61ba95e9df167db19a49b96d41e42e2c6d842f30a6a%40group.calendar.google.com&ctz=Europe%2FMadrid"
|
||||
frameborder="0"
|
||||
scrolling="no"
|
||||
></iframe>
|
||||
<p class="note">Timezone: Europe/Madrid. If you prefer your local timezone, add <code>&ctz=Your%2FTimezone</code> to the URL.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
297
docs/cli_options.rst
Normal file
297
docs/cli_options.rst
Normal file
@@ -0,0 +1,297 @@
|
||||
.. _cli-options:
|
||||
|
||||
***********************************************************
|
||||
`gnpy-path-request` and `gnpy-transmission-example` scripts
|
||||
***********************************************************
|
||||
|
||||
Common options
|
||||
==============
|
||||
|
||||
**Option**: `--no-insert-edfas`
|
||||
-------------------------------
|
||||
|
||||
**Purpose**: Disables the automatic insertion of EDFAs after ROADMs and fibers, as well as the splitting
|
||||
of fibers during the auto-design process.
|
||||
|
||||
The `--no-insert-edfas` option is a command-line argument available in GNPy that allows users to control the
|
||||
automatic insertion of amplifiers during the network design process. This option provides flexibility for
|
||||
users who may want to manually manage amplifier placements or who have specific design requirements that
|
||||
do not necessitate automatic amplification.
|
||||
|
||||
To use the `--no-insert-edfas` option, simply include it in the command line when running your GNPy program. For example:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --no-insert-edfas
|
||||
|
||||
When the `--no-insert-edfas` option is specified:
|
||||
|
||||
1. **No Automatic Amplifiers**: The program will not automatically add EDFAs to the network topology after
|
||||
ROADMs or fiber elements. This means that if the network design requires amplification, users must ensure
|
||||
that amplifiers are manually defined in the network topology file. Users should be aware that disabling
|
||||
automatic amplifier insertion may lead to insufficient amplification in the network if not managed properly.
|
||||
It is essential to ensure that the network topology includes the necessary amplifiers to meet performance requirements.
|
||||
|
||||
2. **No Fiber Splitting**: The option also prevents the automatic splitting of fibers during the design process.
|
||||
This is particularly useful for users who want to maintain specific fiber lengths or configurations without
|
||||
the program altering them.
|
||||
|
||||
|
||||
**Option**: `--equipment`, `-e`
|
||||
-------------------------------
|
||||
|
||||
**Description**: Specifies the equipment library file.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --equipment <FILE.json>
|
||||
|
||||
**Default**: Uses the default equipment configuration in the example-data folder if not specified.
|
||||
|
||||
**Functionality**: This option allows users to load a specific equipment configuration that defines the characteristics of the network elements.
|
||||
|
||||
**Option**: `--extra-equipment` and `--extra-config`
|
||||
----------------------------------------------------
|
||||
|
||||
The `--extra-equipment` and `--extra-config` options allow users to extend the default equipment library and configuration
|
||||
settings used by the GNPy program. This feature is particularly useful for users who need to incorporate additional
|
||||
equipment types or specific configurations that are not included in the standard equipment library (such as third party pluggables).
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
--extra-equipment <file1.json> [<file2.json> ...]
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `<file1.json>`: Path to the first additional equipment file.
|
||||
- `<file2.json>`: Path to any subsequent additional equipment files (optional).
|
||||
|
||||
**Functionality**:
|
||||
|
||||
- The program will merge the equipment definitions from the specified files into the main equipment library.
|
||||
- If an equipment type defined in the additional files has the same name as one in the main library, the program
|
||||
will issue a warning about the duplicate entry and will include ony the last definition.
|
||||
- This allows for flexibility in defining equipment that may be specific to certain use cases or vendor-specific models.
|
||||
|
||||
**`--extra-config`**:
|
||||
|
||||
**Description**: This option allows users to specify additional configuration files that can override
|
||||
or extend the default configuration settings used by the program. This is useful for customizing simulation
|
||||
parameters or equipment settings. To set an amplifier with a specific such config, it must be defined in the
|
||||
library with the keyword "default_config_from_json" filled with the file name containing the config in the case of
|
||||
"variable_gain" amplifier or with the "advanced_config_from_json" for the "advanced_model" amplifier.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
--extra-config <file1.json> [<file2.json> ...]
|
||||
|
||||
**Parameters**:
|
||||
- `<file1.json>`: Path to the first additional configuration file.
|
||||
- `<file2.json>`: Path to any subsequent additional configuration files (optional).
|
||||
|
||||
**Functionality**:
|
||||
The program will load the configurations from the specified files and consider them instead of the
|
||||
default configurations for the amplifiers that use the "default_config_from_json" or "advanced_config_from_json" keywords.
|
||||
|
||||
To run the program with additional equipment and configuration files, you can use the following command:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example --equipment main_equipment.json \
|
||||
--extra-equipment additional_equipment1.json additional_equipment2.json \
|
||||
--extra-config additional_config1.json
|
||||
|
||||
|
||||
In this example:
|
||||
- `main_equipment.json` is the primary equipment file.
|
||||
- `additional_equipment1.json` and `additional_equipment2.json` are additional equipment files that will be merged into the main library.
|
||||
- `additional_config1.json` is an additional configuration file that will override the default settings for the amplifiers pointing to it.
|
||||
|
||||
|
||||
**Option**: `--save-network`
|
||||
----------------------------
|
||||
|
||||
**Description**: Saves the final network configuration to a specified JSON file.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
--save-network <FILE.json>
|
||||
|
||||
**Functionality**: This option allows users to save the network state after the simulation, which can be useful for future reference or analysis.
|
||||
|
||||
|
||||
**Option**: `--save-network-before-autodesign`
|
||||
----------------------------------------------
|
||||
|
||||
**Description**: Dumps the network into a JSON file prior to autodesign.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-path-request my_network.json my_services.json --save-network-before-autodesign <FILE.json>
|
||||
|
||||
**Functionality**: This option is useful for users who want to inspect the network configuration before any automatic design adjustments are made.
|
||||
|
||||
|
||||
**Option**: `--sim-params`
|
||||
--------------------------
|
||||
|
||||
**Description**: Path to the JSON file containing simulation parameters.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --sim-params <FILE.json>
|
||||
|
||||
**Functionality**: The `--sim-params` option is a command-line argument available in GNPy that allows users to specify a
|
||||
JSON file containing simulation parameters. This option is crucial for customizing the behavior of the simulation:
|
||||
the file ``sim_params.json`` contains the tuning parameters used within both the ``gnpy.science_utils.RamanSolver`` and
|
||||
the ``gnpy.science_utils.NliSolver`` for the evaluation of the Raman profile and the NLI generation, respectively.
|
||||
|
||||
The tuning of the parameters is detailed here: :ref:`json input sim-params<sim-params>`.
|
||||
|
||||
|
||||
`gnpy-transmission-example` options
|
||||
===================================
|
||||
|
||||
**Option**: `--show-channels`
|
||||
-----------------------------
|
||||
|
||||
**Description**: Displays the final per-channel OSNR and GSNR summary.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --show-channels
|
||||
|
||||
**Functionality**: This option provides a summary of the optical signal-to-noise ratio (OSNR)
|
||||
and generalized signal-to-noise ratio (GSNR) for each channel after the simulation.
|
||||
|
||||
|
||||
**Option**: `-pl`, `--plot`
|
||||
---------------------------
|
||||
|
||||
**Description**: Generates plots of the results.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json -pl
|
||||
|
||||
**Functionality**: This option allows users to visualize the results of the simulation through graphical plots.
|
||||
|
||||
|
||||
**Option**: `-l`, `--list-nodes`
|
||||
--------------------------------
|
||||
|
||||
**Description**: Lists all transceiver nodes in the network.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json -l
|
||||
|
||||
**Functionality**: This option provides a quick way to view all transceiver nodes present in the network topology.
|
||||
|
||||
**Option**: `-po`, `--power`
|
||||
----------------------------
|
||||
|
||||
**Description**: Specifies the reference channel power in span in dBm.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json -po <value>
|
||||
|
||||
**Functionality**: This option allows users to set the input power level for the reference channel used in the simulation.
|
||||
It replaces the value specified in the `SI` section of the equipment library (:ref:`power_dbm<spectral_info>`).
|
||||
|
||||
|
||||
**Option**: `--spectrum`
|
||||
------------------------
|
||||
|
||||
**Description**: Specifies a user-defined mixed rate spectrum JSON file for propagation.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --spectrum <FILE.json>
|
||||
|
||||
**Functionality**: This option allows users to define a custom spectrum for the simulation, which can
|
||||
include varying channel rates and configurations. More details here: :ref:`mixed-rate<mixed-rate>`.
|
||||
|
||||
|
||||
Options for `path_requests_run`
|
||||
===============================
|
||||
|
||||
The `gnpy-path-request` script provides a simple path computation function that supports routing, transceiver mode selection, and spectrum assignment.
|
||||
|
||||
It supports include and disjoint constraints for the path computation, but does not provide any optimisation.
|
||||
It requires two mandatory arguments: network file and service file (see :ref:`XLS files<excel-service-sheet>` or :ref:`JSON files<legacy-json>`).
|
||||
|
||||
The `gnpy-path-request` computes:
|
||||
|
||||
- design network once and propagate the service requests on this design
|
||||
- computes performance of each request defined in the service file independently from each other, considering full load (based on the request settings),
|
||||
- assigns spectrum for each request according to the remaining spectrum, on a first arrived first served basis.
|
||||
Lack of spectrum leads to blocking, but performance estimation is still returned for information.
|
||||
|
||||
|
||||
**Option**: `-bi`, `--bidir`
|
||||
----------------------------
|
||||
|
||||
**Description**: Indicates that all demands are bidirectional.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-path-request my_network.json my_service.json -e my_equipment.json -bi
|
||||
|
||||
**Functionality**: This option allows users to specify that the performance of the service requests should be
|
||||
computed in both directions (source to destination and destination to source). This forces the 'bidirectional'
|
||||
attribute to true in the service file, possibly affecting feasibility if one direction is not feasible.
|
||||
|
||||
|
||||
**Option**: `-o`, `--output`
|
||||
----------------------------
|
||||
|
||||
**Description**: Stores computation results requests into a JSON or CSV file.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-path-request my_network.json my_service.json -o <FILE.json|FILE.csv>
|
||||
|
||||
**Functionality**: This option allows users to save the results of the path requests into a specified output file
|
||||
for further analysis.
|
||||
|
||||
|
||||
**Option**: `--redesign-per-request`
|
||||
------------------------------------
|
||||
|
||||
**Description**: Redesigns the network for each request using the request as the reference channel
|
||||
(replaces the `SI` section of the equipment library with the request specifications).
|
||||
|
||||
**Usage**:
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-path-request my_network.json my_services.json --redesign-per-request
|
||||
|
||||
**Functionality**: This option enables checking different scenarios for design.
|
||||
@@ -1,7 +1,8 @@
|
||||
.. _concepts:
|
||||
|
||||
*****************************
|
||||
Simulating networks with GNPy
|
||||
=============================
|
||||
*****************************
|
||||
|
||||
Running simulations with GNPy requires three pieces of information:
|
||||
|
||||
@@ -12,7 +13,7 @@ Running simulations with GNPy requires three pieces of information:
|
||||
.. _concepts-topology:
|
||||
|
||||
Network Topology
|
||||
----------------
|
||||
================
|
||||
|
||||
The *topology* acts as a "digital self" of the simulated network.
|
||||
When given a network topology, GNPy can either run a specific simulation as-is, or it can *optimize* the topology before performing the simulation.
|
||||
@@ -34,7 +35,7 @@ The topology is specified via :ref:`XLS files<excel>` or via :ref:`JSON<legacy-j
|
||||
.. _complete-vs-incomplete:
|
||||
|
||||
Fully Specified vs. Partially Designed Networks
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-----------------------------------------------
|
||||
|
||||
Let's consider a simple triangle topology with three :abbr:`PoPs (Points of Presence)` covering three cities:
|
||||
|
||||
@@ -208,7 +209,7 @@ In other cases where the location of amplifier huts is already known, but the sp
|
||||
.. _concepts-equipment:
|
||||
|
||||
The Equipment Library
|
||||
---------------------
|
||||
=====================
|
||||
|
||||
In order to produce an accurate simulation, GNPy needs to know the physical properties of each entity which affects the optical signal.
|
||||
Entries in the equipment library correspond to actual real-world, tangible entities.
|
||||
@@ -231,7 +232,7 @@ GNPy currently does not take into consideration the spectrum filtering penalties
|
||||
.. _concepts-nf-model:
|
||||
|
||||
Amplifier Noise Figure Models
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-----------------------------
|
||||
|
||||
One of the key parameters of an amplifier is the method to use for computing the Noise Figure (NF).
|
||||
GNPy supports several different noise models with varying level of accuracy.
|
||||
@@ -244,7 +245,7 @@ For scenarios where the vendor has not yet contributed an accurate EDFA NF descr
|
||||
.. _nf-model-min-max-NF:
|
||||
|
||||
Min-max NF
|
||||
**********
|
||||
^^^^^^^^^^
|
||||
|
||||
This is an operator-focused model where performance is defined by the *minimal* and *maximal NF*.
|
||||
These are especially suited to model a dual-coil EDFA with a VOA in between.
|
||||
@@ -254,7 +255,7 @@ The worst (maximal) NF applies when the EDFA operates at its minimal gain.
|
||||
This model is suitable for use when the vendor has not provided a more accurate performance description of the EDFA.
|
||||
|
||||
Raman Approximation
|
||||
*******************
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
While GNPy is fully Raman-aware, under certain scenarios it is useful to be able to run a simulation without an accurate Raman description.
|
||||
For these purposes the :ref:`polynomial NF<ext-nf-model-polynomial-NF>` model with :math:`\text{a} = \text{b} = \text{c} = 0`, and :math:`\text{d} = NF` can be used.
|
||||
@@ -262,7 +263,7 @@ For these purposes the :ref:`polynomial NF<ext-nf-model-polynomial-NF>` model wi
|
||||
.. _concepts-simulation:
|
||||
|
||||
Simulation
|
||||
----------
|
||||
==========
|
||||
|
||||
When the network model has been instantiated and the physical properties and operational settings of the actual physical devices are known, GNPy can start simulating how the signal propagate through the optical fiber.
|
||||
|
||||
|
||||
22
docs/conf.py
22
docs/conf.py
@@ -19,6 +19,8 @@
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
@@ -36,6 +38,7 @@ extensions = ['sphinx.ext.autodoc',
|
||||
'sphinxcontrib.bibtex',
|
||||
'sphinx.ext.graphviz',
|
||||
'myst_parser',
|
||||
'sphinx_rtd_theme',
|
||||
]
|
||||
|
||||
myst_enable_extensions = [
|
||||
@@ -84,11 +87,22 @@ todo_include_todos = False
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_theme_options = {
|
||||
'logo': 'images/GNPy-logo.png',
|
||||
'logo_name': False,
|
||||
'prev_next_buttons_location': 'bottom',
|
||||
# Toc options
|
||||
'collapse_navigation': True,
|
||||
'sticky_navigation': True,
|
||||
'navigation_depth': 4,
|
||||
'includehidden': True,
|
||||
'titles_only': False
|
||||
}
|
||||
html_theme_options = {
|
||||
'navigation_depth': 4,
|
||||
}
|
||||
html_favicon = 'images/GNPy-logo.png'
|
||||
|
||||
html_logo = 'images/GNPy-logo.png'
|
||||
|
||||
@@ -101,7 +115,10 @@ html_logo = 'images/GNPy-logo.png'
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = []
|
||||
html_static_path = ['_static']
|
||||
html_css_files = [
|
||||
'custom.css', # Inclure votre fichier CSS personnalisé
|
||||
]
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
@@ -118,6 +135,7 @@ html_sidebars = {
|
||||
]
|
||||
}
|
||||
|
||||
html_secnum_depth = 4
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
.. _excel:
|
||||
|
||||
*****************************
|
||||
Excel (XLS, XLSX) input files
|
||||
=============================
|
||||
*****************************
|
||||
|
||||
``gnpy-transmission-example`` gives the possibility to use an excel input file instead of a json file. The program then will generate the corresponding json file for you.
|
||||
|
||||
@@ -9,21 +10,22 @@ The file named 'meshTopologyExampleV2.xls' is an example.
|
||||
|
||||
In order to work the excel file MUST contain at least 2 sheets:
|
||||
|
||||
- Nodes
|
||||
- Links
|
||||
- `Nodes`
|
||||
- `Links`
|
||||
|
||||
(In progress) The File MAY contain an additional sheet:
|
||||
(In progress) The File MAY contain additional sheets:
|
||||
|
||||
- Eqt
|
||||
- Service
|
||||
- `Eqpt`
|
||||
- `Service`
|
||||
- `Roadms`
|
||||
|
||||
.. _excel-nodes-sheet:
|
||||
|
||||
Nodes sheet
|
||||
-----------
|
||||
`Nodes` sheet
|
||||
=============
|
||||
|
||||
Nodes sheet contains nine columns.
|
||||
Each line represents a 'node' (ROADM site or an in line amplifier site ILA or a Fused)::
|
||||
`Nodes` sheet contains nine columns.
|
||||
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
|
||||
|
||||
@@ -50,15 +52,15 @@ Each line represents a 'node' (ROADM site or an in line amplifier site ILA or a
|
||||
.. _excel-links-sheet:
|
||||
|
||||
Links sheet
|
||||
-----------
|
||||
===========
|
||||
|
||||
Links sheet must contain sixteen columns::
|
||||
|
||||
<-- east cable from a to z --> <-- west from z to -->
|
||||
<-- east cable from a to z --> <-- west from z to a -->
|
||||
NodeA ; NodeZ ; Distance km ; Fiber type ; Lineic att ; Con_in ; Con_out ; PMD ; Cable Id ; Distance km ; Fiber type ; Lineic att ; Con_in ; Con_out ; PMD ; Cable Id
|
||||
|
||||
|
||||
Links sheets MUST contain all links between nodes defined in Nodes sheet.
|
||||
`Links` sheet MUST contain all links between nodes defined in Nodes sheet.
|
||||
Each line represents a 'bidir link' between two nodes. The two directions are represented on a single line with "east cable from a to z" fields and "west from z to a" fields. Values for 'a to z' may be different from values from 'z to a'.
|
||||
Since both direction of a bidir 'a-z' link are described on the same line (east and west), 'z to a' direction MUST NOT be repeated in a different line. If repeated, it will generate another parrallel bidir link between the same end nodes.
|
||||
|
||||
@@ -85,43 +87,42 @@ and a fiber span from node3 to node6::
|
||||
|
||||
- If filled it MUST contain numbers. If empty it is replaced by a default "80" km value.
|
||||
- If value is below 150 km, it is considered as a single (bidirectional) fiber span.
|
||||
- If value is over 150 km the `gnpy-transmission-example`` program will automatically suppose that intermediate span description are required and will generate fiber spans elements with "_1","_2", ... trailing strings which are not visible in the json output. The reason for the splitting is that current edfa usually do not support large span loss. The current assumption is that links larger than 150km will require intermediate amplification. This value will be revisited when Raman amplification is added”
|
||||
- If value is over 150 km or if the loss is greater than 28 dB, the autodesign program
|
||||
will automatically split the span with "_1","_2", ... trailing strings in names.
|
||||
Splitting threshold can be tuned in ["Span"]["max_length"] and ["Span"]["max_loss"] in
|
||||
equipment library.
|
||||
|
||||
- **Fiber type** is not mandatory.
|
||||
|
||||
If filled it must contain types listed in `eqpt_config.json <gnpy/example-data/eqpt_config.json>`_ in "Fiber" list "type_variety".
|
||||
If not filled it takes "SSMF" as default value.
|
||||
|
||||
- **Lineic att** is not mandatory.
|
||||
- **Lineic att** is not mandatory.
|
||||
|
||||
It is the lineic attenuation expressed in dB/km.
|
||||
If filled it must contain positive numbers.
|
||||
If not filled it takes "0.2" dB/km value
|
||||
|
||||
- *Con_in*, *Con_out* are not mandatory.
|
||||
- **Con_in**, **Con_out** are not mandatory.
|
||||
|
||||
They are the connector loss in dB at ingress and egress of the fiber spans.
|
||||
If filled they must contain positive numbers.
|
||||
If not filled they take "0.5" dB default value.
|
||||
|
||||
- *PMD* is not mandatory and and is not used yet.
|
||||
- **PMD** is not mandatory.
|
||||
|
||||
It is the PMD value of the link in ps.
|
||||
If filled they must contain positive numbers.
|
||||
If not filled, it takes "0.1" ps value.
|
||||
|
||||
- *Cable Id* is not mandatory.
|
||||
- **Cable Id** is not mandatory.
|
||||
If filled they must contain strings with the same constraint as "City" names. Its value is used to differenate links having the same end points. In this case different Id should be used. Cable Ids are not meant to be unique in general.
|
||||
|
||||
|
||||
|
||||
|
||||
(in progress)
|
||||
|
||||
.. _excel-equipment-sheet:
|
||||
|
||||
Eqpt sheet
|
||||
----------
|
||||
==========
|
||||
|
||||
The equipment sheet (named "Eqpt") is optional.
|
||||
If provided, it specifies types of boosters and preamplifiers for all ROADM degrees of all ROADM nodes, and for all ILA nodes.
|
||||
@@ -176,7 +177,7 @@ This generates a text file meshTopologyExampleV2_eqt_sheet.txt whose content ca
|
||||
- **Node Z** is mandatory. It is the egress direction from the *Node A* site. Multiple Links between the same Node A and NodeZ is not supported.
|
||||
|
||||
- **amp type** is not mandatory.
|
||||
If filled it must contain types listed in `eqpt_config.json <gnpy/example-data/eqpt_config.json>`_ in "Edfa" list "type_variety".
|
||||
If filled it must contain types listed in the equipment librairie like in the example `eqpt_config.json <gnpy/example-data/eqpt_config.json>`_ in "Edfa" list "type_variety".
|
||||
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.
|
||||
|
||||
@@ -184,22 +185,57 @@ This generates a text file meshTopologyExampleV2_eqt_sheet.txt whose content ca
|
||||
If not filled, it will be determined with design rules in the convert.py file.
|
||||
If filled, it must contain positive numbers.
|
||||
|
||||
- *att_in* and *att_out* are not mandatory and are not used yet. They are the value of the attenuator at input and output of amplifier (in dB).
|
||||
- **att_in** and **att_out** are not mandatory. They are the value of the attenuator at input and output of amplifier (in dB).
|
||||
If filled they must contain positive numbers.
|
||||
|
||||
- **tilt**, in dB, is not mandatory. It is the target gain tilt over the full amplfifier bandwidth and is defined with regard to wavelength, i.e. negative tilt means lower gain
|
||||
for higher wavelengths (lower frequencies). If not filled, the default value is 0.
|
||||
|
||||
- **delta_p**, in dBm, is not mandatory. If filled it is used to set the output target power per channel at the output of the amplifier, if power_mode is True. The output power is then set to power_dbm + delta_power.
|
||||
- **delta_p**, in dB, is not mandatory. If filled it is used to set the output target power per channel at the output of the amplifier, if power_mode is True. The output power is then set to power_dbm + delta_power.
|
||||
|
||||
# to be completed #
|
||||
|
||||
.. _excel-roadms-sheet:
|
||||
|
||||
Roadms sheet
|
||||
============
|
||||
|
||||
The ROADM sheet (named "Roadms") is optional.
|
||||
If provided, it can be used to specify:
|
||||
|
||||
- per channel power target on a specific ROADM degree (*per_degree_pch_out_db*),
|
||||
- ROADM type variety,
|
||||
- impairment ID (identifier) on a particular ROADM path (from degree - to degree).
|
||||
|
||||
This sheet contains six columns:
|
||||
|
||||
Node A ; Node Z ; per degree target power (dBm) ; type_variety ; from degrees ; from degree to degree impairment id
|
||||
|
||||
- **Node A** is mandatory. Name of the ROADM node (as listed in Nodes sheet).
|
||||
Must be a 'ROADM' (Type attribute in Node sheet), its number of occurence may be equal to its degree.
|
||||
|
||||
- **Node Z** is mandatory. Egress direction from the *Node A* ROADM site. Multiple Links between the same Node A
|
||||
and NodeZ is not supported.
|
||||
|
||||
- **per degree target power (dBm)** (optional).
|
||||
If filled it must contain a value in dBm corresponding to :ref:`per_degree_pch_out_db<roadm_json_instance>` on the **Node Z** degree.
|
||||
Defaults to equipment library value if not filled.
|
||||
|
||||
- **type_variety** (optional). Must be the same for all ROADM entries if filled,
|
||||
and defined in the :ref:`equipment library<roadm>`. Defaults to 'default' if not filled.
|
||||
|
||||
- **from degrees** (optional): List of Node names separated by ' | '. Names must be present in Node sheet.
|
||||
Together with Node Z, they define a list of internal path in ROADM for which the impairment ID applies
|
||||
|
||||
- **from degree to degree impairment id** (optional):List of impairment IDs separated by ' | '. Must be filled
|
||||
if **from degrees** is defined.
|
||||
The impairment ID must be defined in the equipment library and be of "express" type.
|
||||
|
||||
(in progress)
|
||||
|
||||
.. _excel-service-sheet:
|
||||
|
||||
Service sheet
|
||||
-------------
|
||||
=============
|
||||
|
||||
Service sheet is optional. It lists the services for which path and feasibility must be computed with ``gnpy-path-request``.
|
||||
|
||||
@@ -213,7 +249,7 @@ Service sheet must contain 11 columns::
|
||||
|
||||
- **Destination** is mandatory. It is the name of the destination node (as listed in Nodes sheet). Source MUST be a ROADM node. (TODO: relax this and accept trx entries)
|
||||
|
||||
- **TRX type** is mandatory. They are the variety type and selected mode of the transceiver to be used for the propagation simulation. These modes MUST be defined in the equipment library. The format of the mode is used as the name of the mode. (TODO: maybe add another mode id on Transceiver library ?). In particular the mode selection defines the channel baudrate to be used for the propagation simulation.
|
||||
- **TRX type** is mandatory. It is the variety type of the transceiver to be used for the propagation simulation. These modes MUST be defined in the equipment library. The format of the mode is used as the name of the mode. (TODO: maybe add another mode id on Transceiver library ?). In particular the mode selection defines the channel baudrate to be used for the propagation simulation.
|
||||
|
||||
- **mode** is optional. If not specified, the program will search for the mode of the defined transponder with the highest baudrate fitting within the spacing value.
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
.. _extending:
|
||||
|
||||
****************************************
|
||||
Extending GNPy with vendor-specific data
|
||||
========================================
|
||||
****************************************
|
||||
|
||||
GNPy ships with an :ref:`equipment library<concepts-equipment>` containing machine-readable datasheets of networking equipment.
|
||||
Vendors who are willing to contribute descriptions of their supported products are encouraged to `submit a patch <https://review.gerrithub.io/Documentation/intro-gerrit-walkthrough-github.html>`__ -- or just :ref:`get in touch with us directly<contributing>`.
|
||||
@@ -11,7 +12,7 @@ This chapter discusses option for modeling performance of :ref:`EDFA amplifiers<
|
||||
.. _extending-edfa:
|
||||
|
||||
EDFAs
|
||||
-----
|
||||
=====
|
||||
|
||||
An accurate description of the :abbr:`EDFA (Erbium-Doped Fiber Amplifier)` and especially its noise characteristics is required.
|
||||
GNPy describes this property in terms of the **Noise Figure (NF)** of an amplifier model as a function of its operating point.
|
||||
@@ -20,7 +21,7 @@ GNPy supports several different :ref:`noise models<concepts-nf-model>`, and vend
|
||||
.. _ext-nf-model-polynomial-NF:
|
||||
|
||||
Polynomial NF
|
||||
*************
|
||||
-------------
|
||||
|
||||
This model computes the NF as a function of the difference between the optimal gain and the current gain.
|
||||
The NF is expressed as a third-degree polynomial:
|
||||
@@ -43,7 +44,7 @@ In that case, use:
|
||||
.. _ext-nf-model-polynomial-OSNR-OpenROADM:
|
||||
|
||||
Polynomial OSNR (OpenROADM-style for inline amplifier)
|
||||
******************************************************
|
||||
------------------------------------------------------
|
||||
|
||||
This model is useful for amplifiers compliant to the OpenROADM specification for ILA (an in-line amplifier).
|
||||
The amplifier performance is evaluated via its incremental OSNR, which is a function of the input power.
|
||||
@@ -55,7 +56,7 @@ The amplifier performance is evaluated via its incremental OSNR, which is a func
|
||||
.. _ext-nf-model-noise-mask-OpenROADM:
|
||||
|
||||
Noise mask (OpenROADM-style for combined preamp and booster)
|
||||
************************************************************
|
||||
------------------------------------------------------------
|
||||
|
||||
Unlike GNPy which simluates the preamplifier and the booster separately as two amplifiers for best accuracy, the OpenROADM specification mandates a certain performance level for a combination of these two amplifiers.
|
||||
For the express path, the effective noise mask comprises the preamplifier and the booster.
|
||||
@@ -70,7 +71,7 @@ GNPy emulates this specification via two special NF models:
|
||||
.. _ext-nf-model-min-max-NF:
|
||||
|
||||
Min-max NF
|
||||
**********
|
||||
----------
|
||||
|
||||
When the vendor prefers not to share the amplifier description in full detail, GNPy also supports describing the NF characteristics via the *minimal* and *maximal NF*.
|
||||
This approximates a more accurate polynomial description reasonably well for some models of a dual-coil EDFA with a VOA in between.
|
||||
@@ -80,7 +81,7 @@ The worst (maximal) NF applies when the EDFA operates at the minimal gain.
|
||||
.. _ext-nf-model-dual-stage-amplifier:
|
||||
|
||||
Dual-stage
|
||||
**********
|
||||
----------
|
||||
|
||||
Dual-stage amplifier combines two distinct amplifiers.
|
||||
Vendors which provide an accurate description of their preamp and booster stages separately can use the dual-stage model for an aggregate description of the whole amplifier.
|
||||
@@ -88,7 +89,7 @@ Vendors which provide an accurate description of their preamp and booster stages
|
||||
.. _ext-nf-model-advanced:
|
||||
|
||||
Advanced Specification
|
||||
**********************
|
||||
----------------------
|
||||
|
||||
The amplifier performance can be further described in terms of gain ripple, NF ripple, and the dynamic gain tilt.
|
||||
When provided, the amplifier characteristic is fine-tuned as a function of carrier frequency. Note that in this advanced
|
||||
@@ -97,7 +98,7 @@ specification tilt is defined vs frequency while tilt_target specified in EDFA i
|
||||
.. _extending-raman:
|
||||
|
||||
Raman Amplifiers
|
||||
----------------
|
||||
================
|
||||
|
||||
An accurate simulation of Raman amplification requires knowledge of:
|
||||
|
||||
@@ -113,7 +114,7 @@ This is also useful to quickly approximate a hybrid EDFA+Raman amplifier.
|
||||
.. _extending-transponder:
|
||||
|
||||
Transponders
|
||||
------------
|
||||
============
|
||||
|
||||
Since transponders are usually capable of operating in a variety of modes, these are described separately.
|
||||
A *mode* usually refers to a particular performance point that is defined by a combination of the symbol rate, modulation format, and :abbr:`FEC (Forward Error Correction)`.
|
||||
@@ -152,7 +153,7 @@ GNPy does not directly track the FEC performance, so the type of chosen FEC is l
|
||||
.. _extending-roadm:
|
||||
|
||||
ROADMs
|
||||
------
|
||||
======
|
||||
|
||||
In a :abbr:`ROADM (Reconfigurable Add/Drop Multiplexer)`, GNPy simulates the impairments of the preamplifiers and boosters of line degrees :ref:`separately<topo-roadm-preamp-booster>`.
|
||||
The set of parameters for each ROADM model therefore includes:
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
.. automodule:: gnpy.tools.json_io
|
||||
.. automodule:: gnpy.tools.plots
|
||||
.. automodule:: gnpy.tools.service_sheet
|
||||
.. automodule:: gnpy.tools.worker_utils
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
API Reference Documentation
|
||||
***************************
|
||||
|
||||
``gnpy`` package
|
||||
================
|
||||
GNPy package
|
||||
============
|
||||
|
||||
.. automodule:: gnpy
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
************************************
|
||||
GNPy: Optical Route Planning Library
|
||||
=====================================================================
|
||||
************************************
|
||||
|
||||
`GNPy <http://github.com/telecominfraproject/gnpy>`_ is an open-source,
|
||||
community-developed library for building route planning and optimization tools
|
||||
@@ -7,20 +8,27 @@ in real-world mesh optical networks. It is based on the Gaussian Noise Model.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
:caption: Contents
|
||||
|
||||
intro
|
||||
intro
|
||||
concepts
|
||||
install
|
||||
cli_options
|
||||
amplifier_models_description
|
||||
json
|
||||
json_instance_examples
|
||||
excel
|
||||
extending
|
||||
about-project
|
||||
model
|
||||
gnpy-api
|
||||
release-notes
|
||||
publications
|
||||
genindex
|
||||
modindex
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
------------------
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
***************
|
||||
Installing GNPy
|
||||
---------------
|
||||
***************
|
||||
|
||||
There are several methods on how to obtain GNPy.
|
||||
The easiest option for a non-developer is probably going via our :ref:`Docker images<install-docker>`.
|
||||
@@ -9,7 +10,7 @@ Note that this needs a :ref:`working installation of Python<install-python>`, fo
|
||||
.. _install-docker:
|
||||
|
||||
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.
|
||||
@@ -35,7 +36,7 @@ Remove that directory if you want to start from scratch.
|
||||
.. _install-python:
|
||||
|
||||
Using Python on your computer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=============================
|
||||
|
||||
**Note**: `gnpy` supports Python 3 only. Python 2 is not supported.
|
||||
`gnpy` requires Python ≥3.8
|
||||
@@ -89,7 +90,7 @@ exact version of Python you are using.
|
||||
.. _install-pip:
|
||||
|
||||
Installing the Python package
|
||||
*****************************
|
||||
-----------------------------
|
||||
|
||||
From within your Anaconda Python 3 environment, you can clone the master branch
|
||||
of the `gnpy` repo and install it with:
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
.. _intro:
|
||||
|
||||
************
|
||||
Introduction
|
||||
============
|
||||
************
|
||||
|
||||
``gnpy`` is a library for building route planning and optimization tools.
|
||||
|
||||
@@ -9,8 +10,9 @@ It ships with a number of example programs. Release versions will ship with
|
||||
fully-functional programs.
|
||||
|
||||
**Note**: *If you are a network operator or involved in route planning and
|
||||
optimization for your organization, please contact project maintainer Jan
|
||||
Kundrát <jkt@jankundrat.com>. gnpy is looking for users with
|
||||
optimization for your organization, please contact project maintainers
|
||||
esther Le Rouzic <esther.lerouzic@orange.com>, Andrea D'Amico <adamico@nec-labs.com>.
|
||||
gnpy is looking for users with
|
||||
specific, delineated use cases to drive requirements for future
|
||||
development.*
|
||||
|
||||
@@ -23,18 +25,18 @@ or to run a planning script to check SNR of several services:
|
||||
:alt: Running a simple simulation example
|
||||
|
||||
By default, the gnpy-transmission-example script operates on a single span network defined in
|
||||
`gnpy/example-data/edfa_example_network.json <../gnpy/example-data/edfa_example_network.json>`_
|
||||
`gnpy/example-data/edfa_example_network.json <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/edfa_example_network.json>`_
|
||||
|
||||
You can specify a different network at the command line as follows. For
|
||||
example, to use the CORONET Global network defined in
|
||||
`gnpy/example-data/CORONET_Global_Topology.json <../gnpy/example-data/CORONET_Global_Topology.json>`_:
|
||||
`gnpy/example-data/CORONET_Global_Topology.json <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/CORONET_Global_Topology.json>`_:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ gnpy-transmission-example $(gnpy-example-data)/CORONET_Global_Topology.json
|
||||
|
||||
It is also possible to use an Excel file input (for example
|
||||
`gnpy/example-data/CORONET_Global_Topology.xls <../gnpy/example-data/CORONET_Global_Topology.xls>`_).
|
||||
`gnpy/example-data/CORONET_Global_Topology.xls <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/CORONET_Global_Topology.xls>`_).
|
||||
The Excel file will be processed into a JSON file with the same prefix.
|
||||
Further details about the Excel data structure are available `in the documentation <excel.rst>`__.
|
||||
|
||||
@@ -55,7 +57,7 @@ interference noise.
|
||||
.. |Pnli| replace:: P\ :sub:`nli`
|
||||
|
||||
Further Instructions for Use
|
||||
----------------------------
|
||||
============================
|
||||
|
||||
Simulations are driven by a set of `JSON <json.rst>`__ or `XLS <excel.rst>`__ files.
|
||||
|
||||
@@ -72,8 +74,8 @@ An experimental support for Raman amplification is available:
|
||||
$(gnpy-example-data)/raman_edfa_example_network.json \
|
||||
--sim $(gnpy-example-data)/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 <../gnpy/example-data/raman_edfa_example_network.json>`_.
|
||||
General numeric parameters for simulation control are provided in the `gnpy/example-data/sim_params.json <../gnpy/example-data/sim_params.json>`_.
|
||||
Configuration of Raman pumps (their frequencies, power and pumping direction) is done via the `RamanFiber element in the network topology <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/raman_edfa_example_network.json>`_.
|
||||
General numeric parameters for simulation control are provided in the `gnpy/example-data/sim_params.json <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/sim_params.json>`_.
|
||||
|
||||
Use ``gnpy-path-request`` to request several paths at once:
|
||||
|
||||
|
||||
402
docs/json.rst
402
docs/json.rst
@@ -11,15 +11,17 @@ Equipment Library
|
||||
|
||||
Design and transmission parameters are defined in a dedicated json file.
|
||||
By default, this information is read from `gnpy/example-data/eqpt_config.json <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/eqpt_config.json>`_.
|
||||
This file defines the equipment libraries that can be customized (EDFAs, fibers, and transceivers).
|
||||
This file defines the equipment libraries that can be customized (Amplifiers, ROADMs, fibers, and transceivers).
|
||||
|
||||
It also defines the simulation parameters (spans, ROADMs, and the spectral information to transmit.)
|
||||
It also defines the simulation parameters (spans and the spectral information to transmit.)
|
||||
|
||||
Examples of instances are commented here :ref:`json instances examples<json-instance-examples>`.
|
||||
|
||||
EDFA
|
||||
~~~~
|
||||
|
||||
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. Various 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``.
|
||||
@@ -35,8 +37,12 @@ can be added and existing ones removed. Three different noise models are availab
|
||||
A detailed JSON configuration file is required (by default `gnpy/example-data/std_medium_gain_advanced_config.json <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/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.
|
||||
6. ``'type_def': 'multi_band'`` defines an amplifier type corresponding to an amplification site composed of multiple amplifier elements, where each amplifies a different band of the spectrum.
|
||||
The ``amplifiers`` list contains the list of single-band amplifier type varieties that can compose such multiband
|
||||
amplifiers. Several options can be listed for the same spectrum band. Only one can be selected
|
||||
for the actual :ref:`Multiband_amplifier<multiband_amps>` element.
|
||||
|
||||
For all amplifier models:
|
||||
For all single band amplifier models:
|
||||
|
||||
+------------------------+-----------+-----------------------------------------+
|
||||
| field | type | description |
|
||||
@@ -55,6 +61,36 @@ For all amplifier models:
|
||||
| | | be used as a manual input (from JSON or |
|
||||
| | | Excel template topology files.) |
|
||||
+------------------------+-----------+-----------------------------------------+
|
||||
| ``f_min`` | (number) | Optional. In :math:`Hz`. Minimum and |
|
||||
| and ``f_max`` | | maximum frequency range for the |
|
||||
| | | amplifier. Signal must fit entirely |
|
||||
| | | within this range (center frequency and |
|
||||
| | | spectrum width). |
|
||||
| | | Default is 191.275e-12 Hz and |
|
||||
| | | 196.125e-12. |
|
||||
+------------------------+-----------+-----------------------------------------+
|
||||
|
||||
Default values are defined for the frequency range for:
|
||||
- noise figure ripple
|
||||
- gain ripple
|
||||
- dynamic gain tilt
|
||||
|
||||
Users can introduce custom values using ``default_config_from_json`` which should be populated with a file name containing the desired parameters.
|
||||
|
||||
|
||||
For multi_band amplifier models:
|
||||
|
||||
+------------------------+-----------+-----------------------------------------+
|
||||
| field | type | description |
|
||||
+========================+===========+=========================================+
|
||||
| ``type_variety`` | (string) | A unique name to ID the amplifier in the|
|
||||
| | | JSON template topology input file. |
|
||||
+------------------------+-----------+-----------------------------------------+
|
||||
| ``allowed_for_design`` | (boolean) | If false, the amplifier will not be |
|
||||
| | | picked by auto-design but it can still |
|
||||
| | | be used as a manual input (from JSON or |
|
||||
| | | Excel template topology files.) |
|
||||
+------------------------+-----------+-----------------------------------------+
|
||||
|
||||
Fiber
|
||||
~~~~~
|
||||
@@ -193,6 +229,9 @@ The modes are defined as follows:
|
||||
+----------------------------+-----------+-----------------------------------------+
|
||||
| ``bit_rate`` | (number) | in bit/s |
|
||||
+----------------------------+-----------+-----------------------------------------+
|
||||
| ``min_spacing`` | (number) | in Hz. Min required slot size for this |
|
||||
| | | mode. |
|
||||
+----------------------------+-----------+-----------------------------------------+
|
||||
| ``roll_off`` | (number) | Pure number between 0 and 1. TX signal |
|
||||
| | | roll-off shape. Used by Raman-aware |
|
||||
| | | simulation code. |
|
||||
@@ -447,14 +486,14 @@ Here is an example:
|
||||
"uid": "roadm SITE1",
|
||||
"type": "Roadm",
|
||||
"type_variety": "detailed_impairments",
|
||||
"params": {
|
||||
"per_degree_impairments": [
|
||||
{
|
||||
"from_degree": "trx SITE1",
|
||||
"to_degree": "east edfa in SITE1 to ILA1",
|
||||
"impairment_id": 1
|
||||
}]
|
||||
}
|
||||
"params": {
|
||||
"per_degree_impairments": [
|
||||
{
|
||||
"from_degree": "trx SITE1",
|
||||
"to_degree": "east edfa in SITE1 to ILA1",
|
||||
"impairment_id": 1
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
It is not permitted to use a roadm-path-impairment-id for the wrong roadm path type (add impairment only for add path).
|
||||
@@ -462,6 +501,8 @@ If nothing is stated for impairments on roadm-paths, the program identifies the
|
||||
|
||||
On the previous example, all «implicit» express roadm-path are assigned roadm-path-impairment-id = 0
|
||||
|
||||
.. _sim-params:
|
||||
|
||||
Global parameters
|
||||
-----------------
|
||||
|
||||
@@ -492,6 +533,19 @@ See ``delta_power_range_db`` for more explaination.
|
||||
| | | mandatory when Raman amplification is |
|
||||
| | | included in the simulation |
|
||||
+---------------------------------------------+-----------+---------------------------------------------+
|
||||
| ``raman_params.method`` | (string) | Model used for Raman evaluation. Valid |
|
||||
| | | choices are ``perturbative`` (see |
|
||||
| | | `arXiv:2304.11756 |
|
||||
| | | <https://arxiv.org/abs/2304.11756>`_) and |
|
||||
| | | ``numerical``, the GNPy legacy first order |
|
||||
| | | derivative numerical solution. |
|
||||
+---------------------------------------------+-----------+---------------------------------------------+
|
||||
|``raman_params.order`` | | Order of the perturbative expansion. |
|
||||
| | | For C- and C+L-band transmission scenarios |
|
||||
| | | the second order provides high accuracy |
|
||||
| | | considering common values of fiber input |
|
||||
| | | power. (Default is 2) |
|
||||
+---------------------------------------------+-----------+---------------------------------------------+
|
||||
| ``raman_params.result_spatial_resolution`` | (number) | Spatial resolution of the output |
|
||||
| | | Raman profile along the entire fiber span. |
|
||||
| | | This affects the accuracy and the |
|
||||
@@ -503,11 +557,18 @@ See ``delta_power_range_db`` for more explaination.
|
||||
| | | channel around 0 dBm, a suggested value of |
|
||||
| | | spatial resolution is 10e3 m |
|
||||
+---------------------------------------------+-----------+---------------------------------------------+
|
||||
| ``raman_params.solver_spatial_resolution`` | (number) | Spatial step for the iterative solution |
|
||||
| | | of the first order differential equation |
|
||||
| | | used to calculate the Raman profile |
|
||||
| | | along the entire fiber span. |
|
||||
| | | This affects the accuracy and the |
|
||||
| ``raman_params.solver_spatial_resolution`` | (number) | When using the ``perturbative`` method, |
|
||||
| | | the step for the spatial integration does |
|
||||
| | | not affect the first order. Therefore, a |
|
||||
| | | large step can be used when no |
|
||||
| | | counter-propagating Raman amplification is |
|
||||
| | | present; a suggested value is 10e3 m. |
|
||||
| | | In presence of counter-propagating Raman |
|
||||
| | | amplification or when using the |
|
||||
| | | ``numerical`` method the following remains |
|
||||
| | | valid. |
|
||||
| | | The spatial step for the iterative solution |
|
||||
| | | affects the accuracy and the |
|
||||
| | | computational time of the evaluated |
|
||||
| | | Raman profile: |
|
||||
| | | smaller the spatial resolution higher both |
|
||||
@@ -523,6 +584,10 @@ See ``delta_power_range_db`` for more explaination.
|
||||
| | | ``ggn_spectrally_separated`` (see eq. 21 |
|
||||
| | | from `arXiv:1710.02225 |
|
||||
| | | <https://arxiv.org/abs/1710.02225>`_). |
|
||||
| | | ``ggn_approx`` (see eq. 24-25 |
|
||||
| | | from `jlt:9741324 |
|
||||
| | | <https://eeexplore.ieee.org/document/ |
|
||||
| | | 9741324>`_). |
|
||||
+---------------------------------------------+-----------+---------------------------------------------+
|
||||
| ``dispersion_tolerance`` | (number) | Optional. Pure number. Tuning parameter for |
|
||||
| | | ggn model solution. Default value is 1. |
|
||||
@@ -669,6 +734,30 @@ Span configuration is not a list (which may change in later releases) and the us
|
||||
| | | value is input in the topology for a |
|
||||
| | | given Fiber. |
|
||||
+-------------------------------------+-----------+---------------------------------------------+
|
||||
| ``span_loss_ref`` | (number) | (optional) in dB. For autodesign. |
|
||||
| | | Reference span loss value in dB, used to |
|
||||
| | | calculate all delta_p deviations during |
|
||||
| | | network autodesign. The default value is |
|
||||
| | | 20dB. |
|
||||
+-------------------------------------+-----------+---------------------------------------------+
|
||||
| ``power_slope`` | (number) | (optional) Pure number. For autodesign. |
|
||||
| | | Ratio used to compute all delta_p |
|
||||
| | | deviations during network autodesign. |
|
||||
| | | The default value is 0.3. |
|
||||
+-------------------------------------+-----------+---------------------------------------------+
|
||||
| ``voa_margin`` | (float) | (optional) in dB. For autodesign. |
|
||||
| | | Margin to subtract from the calculated VOA |
|
||||
| | | during gain optimisation process, to |
|
||||
| | | prevent maximum attenuation. |
|
||||
| | | This creates a safety buffer. |
|
||||
| | | Default value is 1dB. |
|
||||
+-------------------------------------+-----------+---------------------------------------------+
|
||||
| ``voa_step`` | (float) | (optional) in dB. For autodesign. |
|
||||
| | | Step size used for rounding the VOA value. |
|
||||
| | | Ensures VOA adjustments align with hardware |
|
||||
| | | resolution. |
|
||||
| | | Default value is 0.5dB. |
|
||||
+-------------------------------------+-----------+---------------------------------------------+
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@@ -724,74 +813,91 @@ It also defines the channels to be propagated for the gnpy-transmission-example
|
||||
Flexgrid channel partitioning is available since the 2.7 release via the extra ``--spectrum`` option.
|
||||
In the simplest case, homogeneous channel allocation can be defined via the ``SpectralInformation`` construct which defines a spectrum of N identical carriers:
|
||||
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| field | type | description |
|
||||
+======================+===========+===========================================+
|
||||
| ``f_min``, | (number) | In Hz. Define spectrum boundaries. Note |
|
||||
| ``f_max`` | | that due to backward compatibility, the |
|
||||
| | | first channel central frequency is placed |
|
||||
| | | at :math:`f_{min} + spacing` and the last |
|
||||
| | | one at :math:`f_{max}`. |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| ``baud_rate`` | (number) | In Hz. Simulated baud rate. |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| ``spacing`` | (number) | In Hz. Carrier spacing. |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| ``roll_off`` | (number) | Pure number between 0 and 1. TX signal |
|
||||
| | | roll-off shape. Used by Raman-aware |
|
||||
| | | simulation code. |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| ``tx_osnr`` | (number) | In dB. OSNR out from transponder. |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| ``power_dbm`` | (number) | In dBm. Target input power in spans to |
|
||||
| | | be considered for the design |
|
||||
| | | In gain mode |
|
||||
| | | (see spans/power_mode = false), if no |
|
||||
| | | gain is set in an amplifier, auto-design |
|
||||
| | | sets gain to meet this reference |
|
||||
| | | power. If amplifiers gain is set, |
|
||||
| | | ``power_dbm`` is |
|
||||
| | | ignored. |
|
||||
| | | |
|
||||
| | | In power mode, the ``power_dbm`` |
|
||||
| | | is the reference power for |
|
||||
| | | the ``delta_p`` settings in amplifiers. |
|
||||
| | | It is also the reference power for |
|
||||
| | | auto-design power optimisation range |
|
||||
| | | Spans/delta_power_range_db. For example, |
|
||||
| | | if delta_power_range_db = `[0,0,0]`, the |
|
||||
| | | same power=power_dbm is launched in every |
|
||||
| | | spans. The network design is performed |
|
||||
| | | with the power_dbm value: even if a |
|
||||
| | | power sweep is defined (see after) the |
|
||||
| | | design is not repeated. |
|
||||
| | | |
|
||||
| | | If the ``--power`` CLI option is used, |
|
||||
| | | its value replaces this parameter. |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| ``tx_power_dbm`` | (number) | In dBm. Optional. Power out from |
|
||||
| | | transceiver. Default = power_dbm |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| ``power_range_db`` | (number) | Power sweep excursion around |
|
||||
| | | ``power_dbm``. |
|
||||
| | | This defines a list of reference powers |
|
||||
| | | to run the propagation, in the range |
|
||||
| | | power_range_db + power_dbm. |
|
||||
| | | Power sweep uses the ``delta_p`` targets |
|
||||
| | | or, if they have not been set, the ones |
|
||||
| | | computed by auto-design, regardless of |
|
||||
| | | of preceding amplifiers' power |
|
||||
| | | saturation. |
|
||||
| | | |
|
||||
| | | Power sweep is an easy way to find the |
|
||||
| | | optimal reference power. |
|
||||
| | | |
|
||||
| | | Power sweep excursion is ignored in case |
|
||||
| | | of gain mode. |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
| ``sys_margins`` | (number) | In dB. Added margin on min required |
|
||||
| | | transceiver OSNR. |
|
||||
+----------------------+-----------+-------------------------------------------+
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| field | type | description |
|
||||
+=====================================+===========+===========================================+
|
||||
| ``type_variety`` | (string) | Optional. Default: ``default`` |
|
||||
| | | A unique name to ID the band for |
|
||||
| | | propagation or design. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``f_min``, ``f_max`` | (number) | In Hz. Define spectrum boundaries. Note |
|
||||
| | | that due to backward compatibility, the |
|
||||
| | | first channel central frequency is placed |
|
||||
| | | at :math:`f_{min} + spacing` and the last |
|
||||
| | | one at :math:`f_{max}`. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``baud_rate`` | (number) | In Hz. Simulated baud rate. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``spacing`` | (number) | In Hz. Carrier spacing. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``roll_off`` | (number) | Pure number between 0 and 1. TX signal |
|
||||
| | | roll-off shape. Used by Raman-aware |
|
||||
| | | simulation code. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``tx_osnr`` | (number) | In dB. OSNR out from transponder. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``power_dbm`` | (number) | In dBm. Target input power in spans to |
|
||||
| | | be considered for the design |
|
||||
| | | In gain mode |
|
||||
| | | (see spans/power_mode = false), if no |
|
||||
| | | gain is set in an amplifier, auto-design |
|
||||
| | | sets gain to meet this reference |
|
||||
| | | power. If amplifiers gain is set, |
|
||||
| | | ``power_dbm`` is |
|
||||
| | | ignored. |
|
||||
| | | |
|
||||
| | | In power mode, the ``power_dbm`` |
|
||||
| | | is the reference power for |
|
||||
| | | the ``delta_p`` settings in amplifiers. |
|
||||
| | | It is also the reference power for |
|
||||
| | | auto-design power optimisation range |
|
||||
| | | Spans/delta_power_range_db. For example, |
|
||||
| | | if delta_power_range_db = `[0,0,0]`, the |
|
||||
| | | same power=power_dbm is launched in every |
|
||||
| | | spans. The network design is performed |
|
||||
| | | with the power_dbm value: even if a |
|
||||
| | | power sweep is defined (see after) the |
|
||||
| | | design is not repeated. |
|
||||
| | | |
|
||||
| | | If the ``--power`` CLI option is used, |
|
||||
| | | its value replaces this parameter. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``tx_power_dbm`` | (number) | In dBm. Optional. Power out from |
|
||||
| | | transceiver. Default = power_dbm |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``power_range_db`` | (number) | Power sweep excursion around |
|
||||
| | | ``power_dbm``. |
|
||||
| | | This defines a list of reference powers |
|
||||
| | | to run the propagation, in the range |
|
||||
| | | power_range_db + power_dbm. |
|
||||
| | | Power sweep uses the ``delta_p`` targets |
|
||||
| | | or, if they have not been set, the ones |
|
||||
| | | computed by auto-design, regardless of |
|
||||
| | | of preceding amplifiers' power |
|
||||
| | | saturation. |
|
||||
| | | |
|
||||
| | | Power sweep is an easy way to find the |
|
||||
| | | optimal reference power. |
|
||||
| | | |
|
||||
| | | Power sweep excursion is ignored in case |
|
||||
| | | of gain mode. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``sys_margins`` | (number) | In dB. Added margin on min required |
|
||||
| | | transceiver OSNR. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
| ``use_si_channel_count_for_design`` | (boolean) | Optional. If True, the design uses the SI |
|
||||
| | | definition for channel count computation |
|
||||
| | | instead of the amplifier bandwidth. |
|
||||
| | | This option enable to reproduce legacy |
|
||||
| | | behaviour. |
|
||||
+-------------------------------------+-----------+-------------------------------------------+
|
||||
|
||||
It is possible to define a set of bands in the SI block. In this case, type_variety must be used.
|
||||
Each set defines a reference channel used for design functions and autodesign processes.
|
||||
|
||||
If no spectrum is defined (--spectrum or --services), then the same type of reference channel is
|
||||
also used for simulation.
|
||||
|
||||
|
||||
.. _mixed-rate:
|
||||
|
||||
@@ -843,7 +949,7 @@ For example this example:
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"SI":[
|
||||
"spectrum":[
|
||||
{
|
||||
"f_min": 191.4e12,
|
||||
"f_max":193.1e12,
|
||||
@@ -854,7 +960,7 @@ For example this example:
|
||||
},
|
||||
{
|
||||
"f_min": 193.1625e12,
|
||||
"f_max":195e12,
|
||||
"f_max": 195e12,
|
||||
"baud_rate": 64e9,
|
||||
"delta_pdb": 3,
|
||||
"slot_width": 75e9,
|
||||
@@ -1100,6 +1206,8 @@ the maximum achievable total power.
|
||||
|
||||
The exact layout used by simulation can be retrieved thanks to --save-network option.
|
||||
|
||||
.. _operational_field:
|
||||
|
||||
+----------------------+-----------+--------------------------------------------------+
|
||||
| field | type | description |
|
||||
+======================+===========+==================================================+
|
||||
@@ -1155,9 +1263,68 @@ The exact layout used by simulation can be retrieved thanks to --save-network op
|
||||
}
|
||||
}
|
||||
|
||||
.. _multiband_amps:
|
||||
|
||||
Multiband_amplifier attributes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
+----------------------+-----------+--------------------------------------------------+
|
||||
| field | type | description |
|
||||
+======================+===========+==================================================+
|
||||
| ``type`` | (string) | Mandatory: ``Multiband_amplifier`` |
|
||||
+----------------------+-----------+--------------------------------------------------+
|
||||
| ``type_variety`` | (string) | Optional, value must be listed in the library |
|
||||
| | | to be a valid type. If not defined, autodesign |
|
||||
| | | will pick one in the library among the |
|
||||
| | | ``allowed_for_design``. |
|
||||
+----------------------+-----------+--------------------------------------------------+
|
||||
| ``amplifiers`` | (list of | Optional, configuration settings of the |
|
||||
| | dict) | amplifiers composing the multiband amplifier. |
|
||||
| | | Single band amplifier can be set with the |
|
||||
| | | parameters of tables: |
|
||||
| | | :ref:`operational_field<operational_field>`: |
|
||||
+----------------------+-----------+--------------------------------------------------+
|
||||
|
||||
Example of Multiband_amplifier element setting:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"uid": "east edfa in Site_A to Site_B",
|
||||
"type": "Multiband_amplifier",
|
||||
"type_variety": "std_medium_gain_multiband",
|
||||
"amplifiers": [{
|
||||
"type_variety": "std_medium_gain_C",
|
||||
"operational": {
|
||||
"gain_target": 22.55,
|
||||
"delta_p": 0.9,
|
||||
"out_voa": 3.0,
|
||||
"tilt_target": 0.0
|
||||
}
|
||||
}, {
|
||||
"type_variety": "std_medium_gain_L",
|
||||
"operational": {
|
||||
"gain_target": 21,
|
||||
"delta_p": 3.0,
|
||||
"out_voa": 3.0,
|
||||
"tilt_target": 0.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
The frequency band of the element is the concatenation of the bands of each individual amplifier contained in
|
||||
the Multiband_amplifier element. Only carriers within these bands are propagated through the Multiband_amplifier
|
||||
element. If the user defines a spectrum larger than these bands, carriers that do not match the bands will be
|
||||
filtered out. The user can define the bandwidth of the amplifiers in the library. f_min and f_max represent the
|
||||
bandwidth of the amplifier (the entire channel must fit). The individual amplifier type_variety must be part of the
|
||||
allowed ``amplifiers`` list defined in the library.
|
||||
|
||||
Roadm
|
||||
~~~~~
|
||||
|
||||
.. _roadm_json_instance:
|
||||
|
||||
+----------------------------------------+-----------+----------------------------------------------------+
|
||||
| field | type | description |
|
||||
+========================================+===========+====================================================+
|
||||
@@ -1186,32 +1353,69 @@ Roadm
|
||||
| | dict) | defined, it overrides the general values defined |
|
||||
| | | by type_variety. |
|
||||
+----------------------------------------+-----------+----------------------------------------------------+
|
||||
| ``design_bands`` | (list of | Optional. List of bands expressed as dictionnary, |
|
||||
| | dict) | e.g. {"f_min": 191.3e12, "f_max": 195.1e12} |
|
||||
| | | To be considered for autodesign on all degrees of |
|
||||
| | | the ROADM, if nothing is defined on the degrees. |
|
||||
+----------------------------------------+-----------+----------------------------------------------------+
|
||||
| ``per_degree_design_bands`` | (dict of | Optional. If defined, it overrides ROADM's general |
|
||||
| | string, | design_bands, on the degree identified with the |
|
||||
| | list of | key string. Value is a list of bands defined by |
|
||||
| | dict) | their frequency bounds ``f_min`` and ``f_max`` |
|
||||
| | | expressed in THz. |
|
||||
+----------------------------------------+-----------+----------------------------------------------------+
|
||||
|
||||
|
||||
Definition example:
|
||||
|
||||
.. code-block:: json
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"uid": "roadm SITE1",
|
||||
"type": "Roadm",
|
||||
"type_variety": "detailed_impairments",
|
||||
"params": {
|
||||
"per_degree_impairments": [
|
||||
{
|
||||
"from_degree": "trx SITE1",
|
||||
"to_degree": "east edfa in SITE1 to ILA1",
|
||||
"impairment_id": 1
|
||||
}],
|
||||
"per_degree_pch_out_db": {
|
||||
"params": {
|
||||
"per_degree_impairments": [
|
||||
{
|
||||
"from_degree": "trx SITE1",
|
||||
"to_degree": "east edfa in SITE1 to ILA1",
|
||||
"impairment_id": 1
|
||||
}],
|
||||
"per_degree_pch_out_db": {
|
||||
"east edfa in SITE1 to ILA1": -13.5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
In this example, all «implicit» express roadm-path are assigned as roadm-path-impairment-id = 0, and the target power is
|
||||
set according to the value defined in the library except for the direction heading to "east edfa in SITE1 to ILA1", where
|
||||
constant power equalization is used to reach -13.5 dBm target power.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"uid": "roadm SITE1",
|
||||
"type": "Roadm",
|
||||
"params": {
|
||||
"per_degree_design_bands": {
|
||||
"east edfa in SITE1 to ILA1": [
|
||||
{"f_min": 191.3e12, "f_max": 196.0e12},
|
||||
{"f_min": 187.0e12, "f_max": 190.0e12}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
In this example the OMS starting from east edfa in SITE1 to ILA1 is defined as a multiband OMS. This means that
|
||||
if there is no setting in all or some of the amplifiers in the OMS, the autodesign function will select amplifiers
|
||||
from those that have ``multi_band`` ``type_def`` amplifiers.
|
||||
|
||||
The default ``design_bands`` is inferred from the :ref:`SI<spectral_info>` block.
|
||||
|
||||
Note that ``design_bands`` and ``type_variety`` amplifiers must be consistent:
|
||||
- you cannot mix single band and multiband amplifiers on the same OMS;
|
||||
- the frequency range of the amplifiers must include ``design_bands``.
|
||||
|
||||
Fused
|
||||
~~~~~
|
||||
|
||||
@@ -1221,7 +1425,7 @@ A fused element connected to the egress of a ROADM will disable the automatic bo
|
||||
|
||||
Fused ``params`` only contains a ``loss`` value in dB.
|
||||
|
||||
.. code-block:: json
|
||||
.. code-block:: json
|
||||
|
||||
"params": {
|
||||
"loss": 2
|
||||
|
||||
1034
docs/json_instance_examples.rst
Normal file
1034
docs/json_instance_examples.rst
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,11 @@
|
||||
.. _physical-model:
|
||||
|
||||
***************************
|
||||
Physical Model used in GNPy
|
||||
===========================
|
||||
***************************
|
||||
|
||||
QoT-E including ASE noise and NLI accumulation
|
||||
----------------------------------------------
|
||||
==============================================
|
||||
|
||||
The operations of PSE simulative framework are based on the capability to
|
||||
estimate the QoT of one or more channels operating lightpaths over a given
|
||||
@@ -83,7 +84,7 @@ ps/nm/km, the analytical approximation ensures an excellent accuracy
|
||||
with a computational time compatible with real-time operations.
|
||||
|
||||
The Gaussian Noise Model to evaluate the NLI
|
||||
--------------------------------------------
|
||||
============================================
|
||||
|
||||
As previously stated, fiber propagation of multilevel modulation formats
|
||||
relying on the polarization-division-multiplexing generates impairments that
|
||||
|
||||
25
docs/publications.rst
Normal file
25
docs/publications.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
.. _publications:
|
||||
|
||||
************
|
||||
Publications
|
||||
************
|
||||
|
||||
Below is a chronological list of notable publications that emerged from the PSE group's collaborative work.
|
||||
These articles detail the evolution of GNPy and confirm its performance through experimental trials:
|
||||
|
||||
- `G. Grammel, V. Curri, and J. Auge, "Physical Simulation Environment of The Telecommunications Infrastructure Project (TIP)," in Optical Fiber Communication Conference, OSA Technical Digest (online) (Optica Publishing Group, 2018), paper M1D.3. <https://opg.optica.org/abstract.cfm?uri=OFC-2018-M1D.3>`_
|
||||
- `B. D. Taylor, G. Goldfarb, S. Bandyopadhyay, V. Curri, and H. Schmidtke, "Towards a Route Planning Tool for Open Optical Networks in the Telecom Infrastructure Project," in Optical Fiber Communication Conference, OSA Technical Digest (online) (Optica Publishing Group, 2018), paper Tu3E.4. <https://opg.optica.org/abstract.cfm?uri=OFC-2018-Tu3E.4>`_
|
||||
- `M. Filer, M. Cantono, A. Ferrari, G. Grammel, G. Galimberti, and V. Curri, "Multi-Vendor Experimental Validation of an Open Source QoT Estimator for Optical Networks," J. Lightwave Technol. 36, 3073-3082 (2018). <https://opg.optica.org/jlt/abstract.cfm?uri=jlt-36-15-3073>`_
|
||||
- `J. Auge, G. Grammel, E. le Rouzic, V. Curri, G. Galimberti, and J. Powell, "Open optical network planning demonstration," in Optical Fiber Communication Conference (OFC) 2019, OSA Technical Digest (Optica Publishing Group, 2019), paper M3Z.9. <https://opg.optica.org/abstract.cfm?uri=OFC-2019-M3Z.9>`_
|
||||
- `J. Kundrát, A. Campanella, E. Le Rouzic, A. Ferrari, O. Havliš, M. Hažlinský, G. Grammel, G. Galimberti, and V. Curri, "Physical-Layer Awareness: GNPy and ONOS for End-to-End Circuits in Disaggregated Networks," in Optical Fiber Communication Conference (OFC) 2020, OSA Technical Digest (Optica Publishing Group, 2020), paper M3Z.17. <https://opg.optica.org/abstract.cfm?uri=ofc-2020-m3z.17>`_
|
||||
- `A. Ferrari, M. Filer, K. Balasubramanian, Y. Yin, E. Le Rouzic, J. Kundrát, G. Grammel, G. Galimberti, and V. Curri, "Experimental Validation of an Open Source Quality of Transmission Estimator for Open Optical Networks," in Optical Fiber Communication Conference (OFC) 2020, OSA Technical Digest (Optica Publishing Group, 2020), paper W3C.2. <https://opg.optica.org/abstract.cfm?uri=ofc-2020-W3C.2>`_
|
||||
- `A. Ferrari, M. Filer, K. Balasubramanian, Y. Yin, E. Le Rouzic, J. Kundrát, G. Grammel, G. Galimberti, and V. Curri, "GNPy: an open source application for physical layer aware open optical networks," J. Opt. Commun. Netw. 12, C31-C40 (2020). <https://opg.optica.org/jocn/fulltext.cfm?uri=jocn-12-6-C31&id=429003>`_
|
||||
- `A. Ferrari, K. Balasubramanian, M. Filer, Y. Yin, E. Le Rouzic, J. Kundrát, G. Grammel, G. Galimberti, and V. Curri, "Softwarized Optical Transport QoT in Production Optical Network: a Brownfield Validation," 2020 European Conference on Optical Communications (ECOC), Brussels, Belgium, 2020. <https://ieeexplore.ieee.org/document/9333280>`_
|
||||
- `A. Ferrari, K. Balasubramanian, M. Filer, Y. Yin, E. Le Rouzic, J. Kundrát, G. Grammel, G. Galimberti, and V. Curri, "Assessment on the in-field lightpath QoT computation including connector loss uncertainties," in Journal of Optical Communications and Networking, vol. 13, no. 2, pp. A156-A164, February 2021. <https://ieeexplore.ieee.org/document/9308057>`_
|
||||
- `J. Kundrát, E. Le Rouzic, J. Mårtensson, A. Campanella, O. Havliš, A. D’Amico, G. Grammel, G. Galimberti, V. Curri, and J. Vojtěch, "GNPy & YANG: Open APIs for End-to-End Service Provisioning in Optical Networks," in Optical Fiber Communication Conference (OFC) 2021, P. Dong, J. Kani, C. Xie, R. Casellas, C. Cole, and M. Li, eds., OSA Technical Digest (Optica Publishing Group, 2021), paper M1B.6. <https://opg.optica.org/abstract.cfm?uri=ofc-2021-M1B.6>`_
|
||||
- `A. D’Amico, E. London, B. Le Guyader, F. Frank, E. Le Rouzic, E. Pincemin, N. Brochier, and V. Curri, "GNPy experimental validation on flex-grid, flex-rate WDM optical transport scenarios," in Optical Fiber Communication Conference (OFC) 2021, P. Dong, J. Kani, C. Xie, R. Casellas, C. Cole, and M. Li, eds., OSA Technical Digest (Optica Publishing Group, 2021), paper W1G.2. <https://opg.optica.org/abstract.cfm?uri=ofc-2021-W1G.2>`_
|
||||
- `E. Virgillito, R. Braun, D. Breuer, A. Gladisch, V. Curri, and G. Grammel, "Testing TIP Open Source Solutions in Deployed Optical Networks," in Optical Fiber Communication Conference (OFC) 2021, P. Dong, J. Kani, C. Xie, R. Casellas, C. Cole, and M. Li, eds., OSA Technical Digest (Optica Publishing Group, 2021), paper F1C.3. <https://opg.optica.org/abstract.cfm?uri=ofc-2021-F1C.3>`_
|
||||
- `A. D’Amico, E. London, B. Le Guyader, F. Frank, E. Le Rouzic, E. Pincemin, N. Brochier, and V. Curri, "Experimental validation of GNPy in a multi-vendor flex-grid flex-rate WDM optical transport scenario," J. Opt. Commun. Netw. 14, 79-88 (2022). <https://opg.optica.org/jocn/fulltext.cfm?uri=jocn-14-3-79&id=466355>`_
|
||||
- `J. Kundrát, E. Le Rouzic, J. Mårtensson, S. Melin, A. D’Amico, G. Grammel, G. Galimberti, and V. Curri, "GNPy: Lessons Learned and Future Plans [Invited]," in European Conference on Optical Communication (ECOC) 2022, J. Leuthold, C. Harder, B. Offrein, and H. Limberger, eds., Technical Digest Series (Optica Publishing Group, 2022), paper We3B.6. <https://opg.optica.org/abstract.cfm?uri=ECEOC-2022-We3B.6>`_
|
||||
- `G. Grammel, J. Kundrat, E. Le Rouzic, S. Melin, V. Curri, A. D'Amico, R. Manzotti, "Open Optical Networks: the good, the bad and the ugly," 49th European Conference on Optical Communications (ECOC 2023), Hybrid Conference, Glasgow, UK, 2023. <https://ieeexplore.ieee.org/document/10484723>`_
|
||||
- `A. D’Amico, V. Gatto, A. Nespola, G. Borraccini, Y. Jiang, P. Poggiolini, E. Le Rouzic, A. M. L. de Lerma, G. Grammel, R. Manzotti, V. Curri, "GNPy Experimental Validation in a C+L Multiband Optical Multiplex Section," 2024 24th International Conference on Transparent Optical Networks (ICTON), Bari, Italy, 2024. <https://ieeexplore.ieee.org/document/10648172>`_
|
||||
@@ -1,11 +1,269 @@
|
||||
.. _release-notes:
|
||||
|
||||
******************
|
||||
Release change log
|
||||
==================
|
||||
******************
|
||||
|
||||
Each release introduces some changes and new features.
|
||||
|
||||
(prepare text for next release)
|
||||
|
||||
v2.13
|
||||
=====
|
||||
|
||||
**Environment**
|
||||
|
||||
The windows-2019 environment is no more supported.
|
||||
|
||||
**Yang Conversion Utilities**
|
||||
|
||||
This release introduces new conversion utilities to facilitate conversion between YANG and legacy formats,
|
||||
ensuring full compatibility with GNPy. The "legacy" format also benefit from the YANG validation for
|
||||
a stricter verification of input files.
|
||||
Console Script for Yang Conversion: Added a new command-line script to perform Yang format conversions easily.
|
||||
|
||||
**Design Enhancements**
|
||||
|
||||
This release adds the ability to parametrize power target calculations, allowing customization of reference
|
||||
span loss and deviation ratios. It implements the use of a reference channel per OMS (Optical Multiplex Section)
|
||||
instead of total power for design calculations, improving accuracy and performance.
|
||||
It also includes spacing information in design band data to assist in maximum power computation for EDFA
|
||||
targets compution during autodesign.
|
||||
|
||||
**Excel handling**
|
||||
|
||||
XLSX files are now read with openpyxl library (while XLS files are still read with xlrd library). Latest release of
|
||||
xlrd is supported, which solves compatibility issues with anaconda install.
|
||||
|
||||
v2.12
|
||||
=====
|
||||
|
||||
**Important Changes:**
|
||||
|
||||
The default values for EDFA configuration, including frequency range, gain ripple, noise figure ripple, or dynamic gain tilt
|
||||
are now hardcoded in parameters.py and are no longer read from the default_edfa_config.json file (the file has been removed).
|
||||
However, users can define their own custom parameters using the default_config_from_json variable, which should be populated with a file name containing the desired parameter description. This applies to both variable_gain and fixed_gain amplifier types.
|
||||
|
||||
This change streamlines the configuration process but requires users to explicitly set parameters through the new
|
||||
model if the default values do not suit their needs via the --extra-config option.
|
||||
|
||||
v2.11.1
|
||||
-------
|
||||
|
||||
**Environment**
|
||||
|
||||
The macOS-12 environment is no more supported.
|
||||
|
||||
**per degree impairment enabled in xls input**
|
||||
|
||||
This release now read per degre roadm-path impairment from roadm sheet
|
||||
Several optional columns are added: 'type_variety' and 'from degrees'
|
||||
and 'from degree to degree impairment id'.
|
||||
|
||||
- 'from degrees' can contain a list of degrees separated with ' | ', then the
|
||||
'from degree to degree impairment id' must contain a list of ids of the same
|
||||
length.
|
||||
|
||||
Impairment ids are expected to be defined in the ROADM equipment library and
|
||||
from degree must be among the previous node from this ROADM.
|
||||
|
||||
**optimizing computation speed**
|
||||
The computation of path is skipped if the provided include nodes provides
|
||||
a complete explicit path (speeds simulation time).
|
||||
|
||||
v2.11
|
||||
=====
|
||||
|
||||
**New feature**
|
||||
|
||||
A new type_def for amplifiers has been introduced: multi_band. This allows the definition of a
|
||||
multiband amplifier site composed of several amplifiers per band (a typical application is C+L transmission). The
|
||||
release also includes autodesign for links (Optical Multiplex Section, OMS) composed of multi_band amplifiers.
|
||||
Multi_band autodesign includes basic tilt and tilt_target calculation when the Raman flag is enabled with the
|
||||
--sim-params option. The spectrum is demultiplexed before propagation in the amplifier and multiplexed in the output
|
||||
fiber at the amplifier output.
|
||||
|
||||
|
||||
In the library:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"type_variety": "std_medium_gain_C",
|
||||
"f_min": 191.225e12,
|
||||
"f_max": 196.125e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain_L",
|
||||
"f_min": 186.5e12,
|
||||
"f_max": 190.1e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain_multiband",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_medium_gain_C",
|
||||
"std_medium_gain_L"
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
|
||||
In the network topology:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"uid": "east edfa in Site_A to Site_B",
|
||||
"type": "Multiband_amplifier",
|
||||
"type_variety": "std_medium_gain_multiband",
|
||||
"amplifiers": [{
|
||||
"type_variety": "std_medium_gain_C",
|
||||
"operational": {
|
||||
"gain_target": 22.55,
|
||||
"delta_p": 0.9,
|
||||
"out_voa": 3.0,
|
||||
"tilt_target": 0.0
|
||||
}
|
||||
}, {
|
||||
"type_variety": "std_medium_gain_L",
|
||||
"operational": {
|
||||
"gain_target": 21,
|
||||
"delta_p": 3.0,
|
||||
"out_voa": 3.0,
|
||||
"tilt_target": 0.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
**Network design**
|
||||
|
||||
Optionally, users can define a design target per OMS (single or multi-band), with specific frequency ranges.
|
||||
Default design bands are defined in the SI.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"uid": "roadm Site_A",
|
||||
"type": "Roadm",
|
||||
"params": {
|
||||
"target_pch_out_db": -20,
|
||||
"design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12}]
|
||||
}
|
||||
}
|
||||
|
||||
It is possible to define a set of bands in the SI block instead of a single Spectrum Information.
|
||||
In this case type_variety must be used.
|
||||
Each set defines a reference channel used for design functions and autodesign.
|
||||
|
||||
The default design settings for the path-request-run script have been modified.
|
||||
Now, design is performed once for the reference channel defined in the SI block of the eqpt_config,
|
||||
and requests are propagated based on this design.
|
||||
The --redesign-per-request option can be used to restore previous behaviour
|
||||
(design using request channel types).
|
||||
|
||||
The autodesign function has been updated to insert multiband booster, preamp or inline amplifiers based on the OMS
|
||||
nature. If nothing is stated (no amplifier defined in the OMS, no design_bands attribute in the ROADM), then
|
||||
it uses single band Edfas.
|
||||
|
||||
**Propagation**
|
||||
|
||||
Only carriers within the amplifier bandwidth are propagated, improving system coherence. This more rigorous checking
|
||||
of the spectrum to be propagated and the amplifier bandwidth may lead to changes in the total number of channels
|
||||
compared to previous releases. The range can be adjusted by changing the values of ``f_min`` and ``f_max``
|
||||
in the amplifier library.
|
||||
|
||||
|
||||
``f_min`` and ``f_max`` represent the boundary frequencies of the amplification bandwidth (the entire channel must fit
|
||||
within this range).
|
||||
In the example below, a signal center frequency of 190.05THz with a 50GHz width cannot fit within the amplifier band.
|
||||
Note that this has a different meaning in the SI or Transceiver blocks, where ``f_min`` and ``f_max`` refers to the
|
||||
minimum / maximum values of the carrier center frequency.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"type_variety": "std_booster_L",
|
||||
"f_min": 186.55e12,
|
||||
"f_max": 190.05e12,
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 21,
|
||||
"gain_min": 20,
|
||||
"p_max": 21,
|
||||
"nf0": 5,
|
||||
"allowed_for_design": false
|
||||
}
|
||||
|
||||
|
||||
**Display**
|
||||
|
||||
The CLI output for the transmission_main_example now displays the channels used for design and simulation,
|
||||
as well as the tilt target of amplifiers.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Reference used for design: (Input optical power reference in span = 0.00dBm,
|
||||
spacing = 50.00GHz
|
||||
nb_channels = 76)
|
||||
|
||||
Channels propagating: (Input optical power deviation in span = 0.00dB,
|
||||
spacing = 50.00GHz,
|
||||
transceiver output power = 0.00dBm,
|
||||
nb_channels = 76)
|
||||
|
||||
The CLI output displays the settings of each amplifier:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Multiband_amplifier east edfa in Site_A to Site_B
|
||||
type_variety: std_medium_gain_multiband
|
||||
type_variety: std_medium_gain_C type_variety: std_medium_gain_L
|
||||
effective gain(dB): 20.90 effective gain(dB): 22.19
|
||||
(before att_in and before output VOA) (before att_in and before output VOA)
|
||||
tilt-target(dB) 0.00 tilt-target(dB) 0.00
|
||||
noise figure (dB): 6.38 noise figure (dB): 6.19
|
||||
(including att_in) (including att_in)
|
||||
pad att_in (dB): 0.00 pad att_in (dB): 0.00
|
||||
Power In (dBm): -1.08 Power In (dBm): -1.49
|
||||
Power Out (dBm): 19.83 Power Out (dBm): 20.71
|
||||
Delta_P (dB): 0.90 Delta_P (dB): 2.19
|
||||
target pch (dBm): 0.90 target pch (dBm): 3.00
|
||||
actual pch out (dBm): -2.09 actual pch out (dBm): -0.80
|
||||
output VOA (dB): 3.00 output VOA (dB): 3.00
|
||||
|
||||
|
||||
**New feature**
|
||||
|
||||
The preturbative Raman and the approximated GGN models are introduced for a faster evaluation of the Raman and
|
||||
Kerr effects, respectively.
|
||||
These implementation are intended to reduce the computational effort required by multiband transmission scenarios.
|
||||
|
||||
Both the novel models have been validated with exstensive simulations
|
||||
(see `arXiv:2304.11756 <https://arxiv.org/abs/2304.11756>`_ for the new Raman model and
|
||||
`jlt:9741324 <https://eeexplore.ieee.org/document/9741324>`_ for the new NLI model).
|
||||
Additionally, they have been experimentally validated in a laboratory setup composed of commertial equipment
|
||||
(see `icton:10648172 <https://eeexplore.ieee.org/document/10648172>`_).
|
||||
|
||||
|
||||
v2.10
|
||||
=====
|
||||
|
||||
ROADM impairments can be defined per degree and roadm-path type (add, drop or express).
|
||||
Minimum loss when crossing a ROADM is no more 0 dB. It can be set per ROADM degree with roadm-path-impairments.
|
||||
|
||||
@@ -112,7 +370,7 @@ can now be set using a different parameter. It can be set as:
|
||||
}
|
||||
|
||||
v2.9
|
||||
----
|
||||
====
|
||||
|
||||
The revision introduces a major refactor that separates design and propagation. Most of these changes have no impact
|
||||
on the user experience, except the following ones:
|
||||
@@ -157,7 +415,7 @@ contribution). Note that "actual pch out (dBm)" is the actual propagated total p
|
||||
band definition at the output of the amplifier element, including noises and out VOA contribution.
|
||||
|
||||
v2.8
|
||||
----
|
||||
====
|
||||
|
||||
**Spectrum assignment**: requests can now support multiple slots.
|
||||
The definition in service file supports multiple assignments (unchanged syntax):
|
||||
@@ -225,15 +483,15 @@ involute manner to get a vanishing beta3 , and this was a mere artifact for NLI
|
||||
beta2 and beta3, not for total dispersion accumulation). Now, the evaluation of beta2 and beta3 is performed explicitly
|
||||
in the element.py module.
|
||||
|
||||
2. The effective area is provided as a scalar value evaluated at the Fiber reference frequency and properly scaled
|
||||
1. The effective area is provided as a scalar value evaluated at the Fiber reference frequency and properly scaled
|
||||
considering the Fiber refractive indices n1 and n2, and the core radius. These quantities are assumed to be fixed and
|
||||
are hard coded in the parameters.py module. Essential change: The effective area is always scaled along the frequency.
|
||||
|
||||
3. The Raman gain coefficient is properly scaled considering the overlapping of fiber effective area values scaled at
|
||||
1. The Raman gain coefficient is properly scaled considering the overlapping of fiber effective area values scaled at
|
||||
the interacting frequencies. Essential change: In previous version the Raman gain coefficient depends only on
|
||||
the frequency offset.
|
||||
|
||||
4. The nonlinear coefficient ``'gamma'`` is properly scaled considering the refractive index n2 and the scaling
|
||||
1. The nonlinear coefficient ``'gamma'`` is properly scaled considering the refractive index n2 and the scaling
|
||||
effective area. Essential change: As the effective area, the nonlinear coefficient is always scaled along the
|
||||
frequency.
|
||||
|
||||
@@ -266,4 +524,4 @@ the deviation from the general equalisation strategy defined in ROADMs.
|
||||
]
|
||||
|
||||
v2.7
|
||||
----
|
||||
====
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.ansi_escapes: A random subset of ANSI terminal escape codes for colored messages
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.ansi_escapes
|
||||
======================
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.equipment: functionality for specifying equipment
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.equipment
|
||||
===================
|
||||
|
||||
This module contains functionality for specifying equipment.
|
||||
"""
|
||||
from collections import defaultdict
|
||||
from functools import reduce
|
||||
from typing import List
|
||||
|
||||
from gnpy.core.exceptions import EquipmentConfigError
|
||||
from gnpy.core.exceptions import EquipmentConfigError, ConfigurationError
|
||||
|
||||
|
||||
def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=False):
|
||||
@@ -80,3 +88,50 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F
|
||||
|
||||
trx_params = {**default_trx_params}
|
||||
return trx_params
|
||||
|
||||
|
||||
def find_type_variety(amps: List[str], equipment: dict) -> List[str]:
|
||||
"""Returns the multiband type_variety associated with a list of single band type_varieties
|
||||
Args:
|
||||
amps (List[str]): A list of single band type_varieties.
|
||||
equipment (dict): A dictionary containing equipment information.
|
||||
|
||||
Returns:
|
||||
str: an amplifier type variety
|
||||
"""
|
||||
listes = find_type_varieties(amps, equipment)
|
||||
|
||||
_found_type = list(reduce(lambda x, y: set(x) & set(y), listes))
|
||||
# Given a list of single band amplifiers, find the multiband amplifier whose multi_band group
|
||||
# matches. For example, if amps list contains ["a1_LBAND", "a2_CBAND"], with a1.multi_band = [a1_LBAND, a1_CBAND]
|
||||
# and a2.multi_band = [a1_LBAND, a2_CBAND], then:
|
||||
# possible_type_varieties = {"a1_LBAND": ["a1", "a2"], "a2_CBAND": ["a2"]}
|
||||
# listes = [["a1", "a2"], ["a2"]]
|
||||
# and _found_type = [a2]
|
||||
if not _found_type:
|
||||
msg = f'{amps} amps do not belong to the same amp type {listes}'
|
||||
raise ConfigurationError(msg)
|
||||
return _found_type
|
||||
|
||||
|
||||
def find_type_varieties(amps: List[str], equipment: dict) -> List[List[str]]:
|
||||
"""Returns the multiband list of type_varieties associated with a list of single band type_varieties
|
||||
Args:
|
||||
amps (List[str]): A list of single band type_varieties.
|
||||
equipment (dict): A dictionary containing equipment information.
|
||||
|
||||
Returns:
|
||||
List[List[str]]: A list of lists containing the multiband type_varieties
|
||||
associated with each single band type_variety.
|
||||
"""
|
||||
possible_type_varieties = defaultdict(list)
|
||||
for amp_name, amp in equipment['Edfa'].items():
|
||||
if amp.multi_band is not None:
|
||||
for elem in amp.multi_band:
|
||||
# possible_type_varieties stores the list of multiband amp names that list this elem as
|
||||
# a possible amplifier of the multiband group. For example, if "std_medium_gain_multiband"
|
||||
# and "std_medium_gain_multiband_new" contain "std_medium_gain_C" in their "multi_band" list, then:
|
||||
# possible_type_varieties["std_medium_gain_C"] =
|
||||
# ["std_medium_gain_multiband", "std_medium_gain_multiband_new"]
|
||||
possible_type_varieties[elem].append(amp_name)
|
||||
return [possible_type_varieties[a] for a in amps]
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.exceptions: Exceptions thrown by other gnpy modules
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.exceptions
|
||||
====================
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.info: classes for modelling Spectral Information
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.info
|
||||
==============
|
||||
@@ -11,7 +16,7 @@ This module contains classes for modelling :class:`SpectralInformation`.
|
||||
from __future__ import annotations
|
||||
from collections import namedtuple
|
||||
from collections.abc import Iterable
|
||||
from typing import Union
|
||||
from typing import Union, List, Optional
|
||||
from dataclasses import dataclass
|
||||
from numpy import argsort, mean, array, append, ones, ceil, any, zeros, outer, full, ndarray, asarray
|
||||
|
||||
@@ -317,6 +322,56 @@ def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, spacing
|
||||
tx_osnr=tx_osnr, tx_power=tx_power, label=label)
|
||||
|
||||
|
||||
def is_in_band(frequency: float, band: dict) -> bool:
|
||||
"""band has {"f_min": value, "f_max": value} format
|
||||
"""
|
||||
if frequency >= band['f_min'] and frequency <= band['f_max']:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def demuxed_spectral_information(input_si: SpectralInformation, band: dict) -> Optional[SpectralInformation]:
|
||||
"""extract a si based on band
|
||||
"""
|
||||
filtered_indices = [i for i, f in enumerate(input_si.frequency)
|
||||
if is_in_band(f - input_si.slot_width[i] / 2, band)
|
||||
and is_in_band(f + input_si.slot_width[i] / 2, band)]
|
||||
if filtered_indices:
|
||||
frequency = input_si.frequency[filtered_indices]
|
||||
baud_rate = input_si.baud_rate[filtered_indices]
|
||||
slot_width = input_si.slot_width[filtered_indices]
|
||||
signal = input_si.signal[filtered_indices]
|
||||
nli = input_si.nli[filtered_indices]
|
||||
ase = input_si.ase[filtered_indices]
|
||||
roll_off = input_si.roll_off[filtered_indices]
|
||||
chromatic_dispersion = input_si.chromatic_dispersion[filtered_indices]
|
||||
pmd = input_si.pmd[filtered_indices]
|
||||
pdl = input_si.pdl[filtered_indices]
|
||||
latency = input_si.latency[filtered_indices]
|
||||
delta_pdb_per_channel = input_si.delta_pdb_per_channel[filtered_indices]
|
||||
tx_osnr = input_si.tx_osnr[filtered_indices]
|
||||
tx_power = input_si.tx_power[filtered_indices]
|
||||
label = input_si.label[filtered_indices]
|
||||
|
||||
return SpectralInformation(frequency=frequency, baud_rate=baud_rate, slot_width=slot_width, signal=signal,
|
||||
nli=nli, ase=ase, roll_off=roll_off, chromatic_dispersion=chromatic_dispersion,
|
||||
pmd=pmd, pdl=pdl, latency=latency, delta_pdb_per_channel=delta_pdb_per_channel,
|
||||
tx_osnr=tx_osnr, tx_power=tx_power, label=label)
|
||||
return None
|
||||
|
||||
|
||||
def muxed_spectral_information(input_si_list: List[SpectralInformation]) -> SpectralInformation:
|
||||
"""return the assembled spectrum
|
||||
"""
|
||||
if input_si_list and len(input_si_list) > 1:
|
||||
si = input_si_list[0] + muxed_spectral_information(input_si_list[1:])
|
||||
return si
|
||||
elif input_si_list and len(input_si_list) == 1:
|
||||
return input_si_list[0]
|
||||
else:
|
||||
raise ValueError('liste vide')
|
||||
|
||||
|
||||
def carriers_to_spectral_information(initial_spectrum: dict[float, Carrier],
|
||||
power: float) -> SpectralInformation:
|
||||
"""Initial spectrum is a dict with key = carrier frequency, and value a Carrier object.
|
||||
|
||||
1986
gnpy/core/network.py
1986
gnpy/core/network.py
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.parameters: parameters to configure standard network elements
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.parameters
|
||||
====================
|
||||
@@ -8,7 +13,8 @@ gnpy.core.parameters
|
||||
This module contains all parameters to configure standard network elements.
|
||||
"""
|
||||
from collections import namedtuple
|
||||
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass
|
||||
from scipy.constants import c, pi
|
||||
from numpy import asarray, array, exp, sqrt, log, outer, ones, squeeze, append, flip, linspace, full
|
||||
|
||||
@@ -35,25 +41,32 @@ class PumpParams(Parameters):
|
||||
|
||||
|
||||
class RamanParams(Parameters):
|
||||
def __init__(self, flag=False, result_spatial_resolution=10e3, solver_spatial_resolution=50):
|
||||
def __init__(self, flag=False, method='perturbative', order=2, result_spatial_resolution=10e3,
|
||||
solver_spatial_resolution=10e3):
|
||||
"""Simulation parameters used within the Raman Solver
|
||||
|
||||
:params flag: boolean for enabling/disable the evaluation of the Raman power profile in frequency and position
|
||||
:params method: Raman solver method
|
||||
:params order: solution order for perturbative method
|
||||
:params result_spatial_resolution: spatial resolution of the evaluated Raman power profile
|
||||
:params solver_spatial_resolution: spatial step for the iterative solution of the first order ode
|
||||
"""
|
||||
self.flag = flag
|
||||
self.method = method
|
||||
self.order = order
|
||||
self.result_spatial_resolution = result_spatial_resolution # [m]
|
||||
self.solver_spatial_resolution = solver_spatial_resolution # [m]
|
||||
|
||||
def to_json(self):
|
||||
return {"flag": self.flag,
|
||||
"method": self.method,
|
||||
"order": self.order,
|
||||
"result_spatial_resolution": self.result_spatial_resolution,
|
||||
"solver_spatial_resolution": self.solver_spatial_resolution}
|
||||
|
||||
|
||||
class NLIParams(Parameters):
|
||||
def __init__(self, method='gn_model_analytic', dispersion_tolerance=1, phase_shift_tolerance=0.1,
|
||||
def __init__(self, method='gn_model_analytic', dispersion_tolerance=4, phase_shift_tolerance=0.1,
|
||||
computed_channels=None, computed_number_of_channels=None):
|
||||
"""Simulation parameters used within the Nli Solver
|
||||
|
||||
@@ -117,6 +130,8 @@ class RoadmParams(Parameters):
|
||||
except KeyError as e:
|
||||
raise ParametersError(f'ROADM configurations must include {e}. Configuration: {kwargs}')
|
||||
self.per_degree_impairments = kwargs.get('per_degree_impairments', [])
|
||||
self.design_bands = kwargs.get('design_bands', [])
|
||||
self.per_degree_design_bands = kwargs.get('per_degree_design_bands', {})
|
||||
|
||||
def get_roadm_path_impairments(self, path_impairments_list):
|
||||
"""Get the ROADM list of profiles for impairments definition
|
||||
@@ -134,7 +149,7 @@ class RoadmParams(Parameters):
|
||||
for path_impairment in path_impairments_list:
|
||||
index = path_impairment['roadm-path-impairments-id']
|
||||
path_type = next(key for key in path_impairment if key in authorized_path_types.keys())
|
||||
impairment_dict = dict({'path-type': authorized_path_types[path_type]}, **path_impairment[path_type][0])
|
||||
impairment_dict = {'path-type': authorized_path_types[path_type], 'impairment': path_impairment[path_type]}
|
||||
roadm_path_impairments[index] = RoadmImpairment(impairment_dict)
|
||||
return roadm_path_impairments
|
||||
|
||||
@@ -155,26 +170,24 @@ class RoadmPath:
|
||||
|
||||
class RoadmImpairment:
|
||||
"""Generic definition of impairments for express, add and drop"""
|
||||
default_values = {
|
||||
'roadm-pmd': None,
|
||||
'roadm-cd': None,
|
||||
'roadm-pdl': None,
|
||||
'roadm-inband-crosstalk': None,
|
||||
'roadm-maxloss': 0,
|
||||
'roadm-osnr': None,
|
||||
'roadm-pmax': None,
|
||||
'roadm-noise-figure': None,
|
||||
'minloss': None,
|
||||
'typloss': None,
|
||||
'pmin': None,
|
||||
'ptyp': None
|
||||
}
|
||||
|
||||
def __init__(self, params):
|
||||
"""Records roadm internal paths and types"""
|
||||
self.path_type = params.get('path-type')
|
||||
self.pmd = params.get('roadm-pmd')
|
||||
self.cd = params.get('roadm-cd')
|
||||
self.pdl = params.get('roadm-pdl')
|
||||
self.inband_crosstalk = params.get('roadm-inband-crosstalk')
|
||||
self.maxloss = params.get('roadm-maxloss', 0)
|
||||
if params.get('frequency-range') is not None:
|
||||
self.fmin = params.get('frequency-range')['lower-frequency']
|
||||
self.fmax = params.get('frequency-range')['upper-frequency']
|
||||
else:
|
||||
self.fmin, self.fmax = None, None
|
||||
self.osnr = params.get('roadm-osnr', None)
|
||||
self.pmax = params.get('roadm-pmax', None)
|
||||
self.nf = params.get('roadm-noise-figure', None)
|
||||
self.minloss = params.get('minloss', None)
|
||||
self.typloss = params.get('typloss', None)
|
||||
self.pmin = params.get('pmin', None)
|
||||
self.ptyp = params.get('ptyp', None)
|
||||
self.impairments = params['impairment']
|
||||
|
||||
|
||||
class FusedParams(Parameters):
|
||||
@@ -335,6 +348,7 @@ class FiberParams(Parameters):
|
||||
|
||||
# Polarization Mode Dispersion
|
||||
self._pmd_coef = kwargs['pmd_coef'] # s/sqrt(m)
|
||||
self._pmd_coef_defined = kwargs.get('pmd_coef_defined', kwargs['pmd_coef'] is True)
|
||||
|
||||
# Loss Coefficient
|
||||
if isinstance(kwargs['loss_coef'], dict):
|
||||
@@ -420,6 +434,10 @@ class FiberParams(Parameters):
|
||||
def pmd_coef(self):
|
||||
return self._pmd_coef
|
||||
|
||||
@property
|
||||
def pmd_coef_defined(self):
|
||||
return self._pmd_coef_defined
|
||||
|
||||
@property
|
||||
def ref_wavelength(self):
|
||||
return self._ref_wavelength
|
||||
@@ -463,10 +481,10 @@ class FiberParams(Parameters):
|
||||
|
||||
class EdfaParams:
|
||||
default_values = {
|
||||
'f_min': 191.3e12,
|
||||
'f_max': 196.1e12,
|
||||
'f_min': None,
|
||||
'f_max': None,
|
||||
'multi_band': None,
|
||||
'bands': [],
|
||||
'bands': None,
|
||||
'type_variety': '',
|
||||
'type_def': '',
|
||||
'gain_flatmax': None,
|
||||
@@ -502,9 +520,11 @@ class EdfaParams:
|
||||
# Bandwidth
|
||||
self.f_min = params['f_min']
|
||||
self.f_max = params['f_max']
|
||||
self.bandwidth = self.f_max - self.f_min
|
||||
self.f_cent = (self.f_max + self.f_min) / 2
|
||||
self.bandwidth = self.f_max - self.f_min if self.f_max and self.f_min else None
|
||||
self.f_cent = (self.f_max + self.f_min) / 2 if self.f_max and self.f_min else None
|
||||
self.f_ripple_ref = params['f_ripple_ref']
|
||||
self.bands = [{'f_min': params['f_min'],
|
||||
'f_max': params['f_max']}]
|
||||
|
||||
# Gain
|
||||
self.gain_flatmax = params['gain_flatmax']
|
||||
@@ -552,7 +572,9 @@ class EdfaParams:
|
||||
else:
|
||||
self.nf_ripple = asarray(nf_ripple)
|
||||
if self.nf_ripple.size != self.gain_ripple.size:
|
||||
raise ParametersError("The noise figure ripple and the gain ripple must have the same size.")
|
||||
raise ParametersError(
|
||||
"The noise figure ripple and the gain ripple must have the same size. %s, %s",
|
||||
self.nf_ripple.size, self.gain_ripple.size)
|
||||
|
||||
# VOA
|
||||
self.out_voa_auto = params['out_voa_auto']
|
||||
@@ -591,7 +613,7 @@ class EdfaParams:
|
||||
|
||||
def update_params(self, kwargs):
|
||||
for k, v in kwargs.items():
|
||||
setattr(self, k, self.update_params(**v) if isinstance(v, dict) else v)
|
||||
setattr(self, k, v)
|
||||
|
||||
|
||||
class EdfaOperational:
|
||||
@@ -599,7 +621,8 @@ class EdfaOperational:
|
||||
'gain_target': None,
|
||||
'delta_p': None,
|
||||
'out_voa': None,
|
||||
'tilt_target': 0
|
||||
'in_voa': 0,
|
||||
'tilt_target': None
|
||||
}
|
||||
|
||||
def __init__(self, **operational):
|
||||
@@ -614,3 +637,95 @@ class EdfaOperational:
|
||||
return (f'{type(self).__name__}('
|
||||
f'gain_target={self.gain_target!r}, '
|
||||
f'tilt_target={self.tilt_target!r})')
|
||||
|
||||
|
||||
DEFAULT_EDFA_CONFIG = {
|
||||
"nf_ripple": [
|
||||
0.0
|
||||
],
|
||||
"gain_ripple": [
|
||||
0.0
|
||||
],
|
||||
"f_min": 191.275e12,
|
||||
"f_max": 196.125e12,
|
||||
"dgt": [
|
||||
1.0, 1.017807767853702, 1.0356155337864215, 1.0534217504465226, 1.0712204022764056, 1.0895983485572227,
|
||||
1.108555289615659, 1.1280891949729075, 1.1476135933863398, 1.1672278304018044, 1.1869318618366975,
|
||||
1.2067249615595257, 1.2264996957264114, 1.2428104897182262, 1.2556591482982988, 1.2650555289898042,
|
||||
1.2744470198196236, 1.2838336236692311, 1.2932153453410835, 1.3040618749785347, 1.316383926863083,
|
||||
1.3301807335621048, 1.3439818461440451, 1.3598972673004606, 1.3779439775587023, 1.3981208704326855,
|
||||
1.418273806730323, 1.4340878115214444, 1.445565137158368, 1.45273959485914, 1.4599103316162523,
|
||||
1.4670307626366115, 1.474100442252211, 1.48111939735681, 1.488134243479226, 1.495145456062699,
|
||||
1.502153039909686, 1.5097346239790443, 1.5178910621476225, 1.5266220576235803, 1.5353620432989845,
|
||||
1.545374152761467, 1.5566577309558969, 1.569199764184379, 1.5817353179379183, 1.5986915141218316,
|
||||
1.6201194134191075, 1.6460167077689267, 1.6719047669939942, 1.6918150918099673, 1.7057507692361864,
|
||||
1.7137640932265894, 1.7217732861435076, 1.7297783508684146, 1.737780757913635, 1.7459181197626403,
|
||||
1.7541903672600494, 1.7625959636196327, 1.7709972329654864, 1.7793941781790852, 1.7877868031023945,
|
||||
1.7961751115773796, 1.8045606557581335, 1.8139629377087627, 1.824381436842932, 1.835814081380705,
|
||||
1.847275503201129, 1.862235672444246, 1.8806927939516411, 1.9026104247588487, 1.9245345552113182,
|
||||
1.9482128147680253, 1.9736443063300082, 2.0008103857988204, 2.0279625371819305, 2.055100772005235,
|
||||
2.082225099873648, 2.1183028432496016, 2.16337565384239, 2.2174389328192197, 2.271520771371253,
|
||||
2.322373696229342, 2.3699990328716107, 2.414398437185221, 2.4587748041127506, 2.499446286796604,
|
||||
2.5364027376452056, 2.5696460593920065, 2.602860350286428, 2.630396440815385, 2.6521732021128046,
|
||||
2.6681935771243177, 2.6841217449620203, 2.6947834587664494, 2.705443819238505, 2.714526681131686
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class MultiBandParams:
|
||||
default_values = {
|
||||
'bands': [],
|
||||
'type_variety': '',
|
||||
'type_def': None,
|
||||
'allowed_for_design': False
|
||||
}
|
||||
|
||||
def __init__(self, **params):
|
||||
try:
|
||||
self.update_attr(params)
|
||||
except KeyError as e:
|
||||
raise ParametersError(f'Multiband configurations json must include {e}. Configuration: {params}')
|
||||
|
||||
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():
|
||||
# use deepcopy to avoid sharing same object amongst all instance when v is a list or a dict!
|
||||
if isinstance(v, (list, dict)):
|
||||
setattr(self, k, clean_kwargs.get(k, deepcopy(v)))
|
||||
else:
|
||||
setattr(self, k, clean_kwargs.get(k, v))
|
||||
|
||||
|
||||
class TransceiverParams:
|
||||
def __init__(self, **params):
|
||||
self.design_bands = params.get('design_bands', [])
|
||||
self.per_degree_design_bands = params.get('per_degree_design_bands', {})
|
||||
|
||||
|
||||
@dataclass
|
||||
class FrequencyBand:
|
||||
"""Frequency band
|
||||
"""
|
||||
f_min: float
|
||||
f_max: float
|
||||
|
||||
|
||||
DEFAULT_BANDS_DEFINITION = {
|
||||
"LBAND": FrequencyBand(f_min=187e12, f_max=189e12),
|
||||
"CBAND": FrequencyBand(f_min=191.3e12, f_max=196.0e12)
|
||||
}
|
||||
# use this definition to index amplifiers'element of a multiband amplifier.
|
||||
# this is not the design band
|
||||
|
||||
|
||||
def find_band_name(band: FrequencyBand) -> str:
|
||||
"""return the default band name (CBAND, LBAND, ...) that corresponds to the band frequency range
|
||||
Use the band center frequency: if center frequency is inside the band then returns CBAND.
|
||||
This is to flexibly encompass all kind of bands definitions.
|
||||
returns the first matching band name.
|
||||
"""
|
||||
for band_name, frequency_range in DEFAULT_BANDS_DEFINITION.items():
|
||||
center_frequency = (band.f_min + band.f_max) / 2
|
||||
if center_frequency >= frequency_range.f_min and center_frequency <= frequency_range.f_max:
|
||||
return band_name
|
||||
return 'unknown_band'
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.science_utils: Solver definitions to calculate the Raman effect and the nonlinear interference noise
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.science_utils
|
||||
=======================
|
||||
@@ -12,14 +17,14 @@ The solvers take as input instances of the spectral information, the fiber and t
|
||||
|
||||
from numpy import interp, pi, zeros, cos, array, append, ones, exp, arange, sqrt, trapz, arcsinh, clip, abs, sum, \
|
||||
concatenate, flip, outer, inner, transpose, max, format_float_scientific, diag, sort, unique, argsort, cumprod, \
|
||||
polyfit
|
||||
polyfit, log, reshape, swapaxes, full, nan, cumsum
|
||||
from logging import getLogger
|
||||
from scipy.constants import k, h
|
||||
from scipy.interpolate import interp1d
|
||||
from math import isclose
|
||||
from math import isclose, factorial
|
||||
|
||||
from gnpy.core.utils import db2lin, lin2db
|
||||
from gnpy.core.exceptions import EquipmentConfigError
|
||||
from gnpy.core.exceptions import EquipmentConfigError, ParametersError
|
||||
from gnpy.core.parameters import SimParams
|
||||
from gnpy.core.info import SpectralInformation
|
||||
|
||||
@@ -136,15 +141,17 @@ class RamanSolver:
|
||||
co_cr = fiber.cr(co_frequency)
|
||||
co_alpha = fiber.alpha(co_frequency)
|
||||
co_power_profile = \
|
||||
RamanSolver.first_order_derivative_solution(co_power, co_alpha, co_cr, z, lumped_losses)
|
||||
RamanSolver.calculate_unidirectional_stimulated_raman_scattering(co_power, co_alpha, co_cr, z,
|
||||
lumped_losses)
|
||||
# Counter-propagating profile initialization
|
||||
cnt_power_profile = zeros([cnt_frequency.size, z.size])
|
||||
if cnt_frequency.size:
|
||||
cnt_cr = fiber.cr(cnt_frequency)
|
||||
cnt_alpha = fiber.alpha(cnt_frequency)
|
||||
cnt_power_profile = \
|
||||
flip(RamanSolver.first_order_derivative_solution(cnt_power, cnt_alpha, cnt_cr,
|
||||
z[-1] - flip(z), flip(lumped_losses)), axis=1)
|
||||
cnt_power_profile = flip(
|
||||
RamanSolver.calculate_unidirectional_stimulated_raman_scattering(cnt_power, cnt_alpha, cnt_cr,
|
||||
z[-1] - flip(z),
|
||||
flip(lumped_losses)), axis=1)
|
||||
# Co-propagating and Counter-propagating Profile Computation
|
||||
if co_frequency.size and cnt_frequency.size:
|
||||
co_power_profile, cnt_power_profile = \
|
||||
@@ -163,8 +170,9 @@ class RamanSolver:
|
||||
alpha = fiber.alpha(spectral_info.frequency)
|
||||
cr = fiber.cr(spectral_info.frequency)
|
||||
# Power profile
|
||||
power_profile = \
|
||||
RamanSolver.first_order_derivative_solution(spectral_info.signal, alpha, cr, z, lumped_losses)
|
||||
power_profile = (
|
||||
RamanSolver.calculate_unidirectional_stimulated_raman_scattering(spectral_info.signal, alpha, cr, z,
|
||||
lumped_losses))
|
||||
# Loss profile
|
||||
loss_profile = power_profile / outer(spectral_info.signal, ones(z.size))
|
||||
frequency = spectral_info.frequency
|
||||
@@ -200,8 +208,8 @@ class RamanSolver:
|
||||
return ase
|
||||
|
||||
@staticmethod
|
||||
def first_order_derivative_solution(power_in, alpha, cr, z, lumped_losses):
|
||||
"""Solves the Raman first order derivative equation
|
||||
def calculate_unidirectional_stimulated_raman_scattering(power_in, alpha, cr, z, lumped_losses):
|
||||
"""Solves the Raman equation
|
||||
|
||||
:param power_in: launch power array
|
||||
:param alpha: loss coefficient array
|
||||
@@ -210,18 +218,66 @@ class RamanSolver:
|
||||
:param lumped_losses: concentrated losses array along the fiber span
|
||||
:return: power profile matrix
|
||||
"""
|
||||
dz = z[1:] - z[:-1]
|
||||
power = outer(power_in, ones(z.size))
|
||||
for i in range(1, z.size):
|
||||
power[:, i] = \
|
||||
power[:, i - 1] * (1 + (- alpha + sum(cr * power[:, i - 1], 1)) * dz[i - 1]) * lumped_losses[i - 1]
|
||||
if sim_params.raman_params.method == 'perturbative':
|
||||
if sim_params.raman_params.order > 4:
|
||||
raise ValueError(f'Order {sim_params.raman_params.order} not implemented in Raman Solver.')
|
||||
z_lumped_losses = append(z[lumped_losses != 1], z[-1])
|
||||
llumped_losses = append(1, lumped_losses[lumped_losses != 1])
|
||||
power = outer(power_in, ones(z.size))
|
||||
last_position = 0
|
||||
z_indices = arange(0, z.size)
|
||||
|
||||
for z_lumped_loss, lumped_loss in zip(z_lumped_losses, llumped_losses):
|
||||
if last_position < z[-1]:
|
||||
interval = z_indices[(z >= last_position) * (z <= z_lumped_loss) == 1]
|
||||
z_interval = z[interval] - last_position
|
||||
dz = z_interval[1:] - z_interval[:-1]
|
||||
last_position = z[interval][-1]
|
||||
p0 = power_in * lumped_loss
|
||||
power_interval = outer(p0, ones(z_interval.size))
|
||||
alphaz = outer(alpha, z_interval)
|
||||
expz = exp(- alphaz)
|
||||
eff_length = 1 / outer(alpha, ones(z_interval.size)) * (1 - expz)
|
||||
crpz = transpose(ones([z_interval.size, cr.shape[0], cr.shape[1]]) * cr * p0, (1, 2, 0))
|
||||
exponent = - alphaz
|
||||
if sim_params.raman_params.order >= 1:
|
||||
gamma1 = sum(crpz * eff_length, 1)
|
||||
exponent += gamma1
|
||||
if sim_params.raman_params.order >= 2:
|
||||
z_integrand = expz * gamma1
|
||||
z_integral = cumsum((z_integrand[:, :-1] + z_integrand[:, 1:]) / 2 * dz, 1)
|
||||
gamma2 = zeros(gamma1.shape)
|
||||
gamma2[:, 1:] = sum(crpz[:, :, 1:] * z_integral, 1)
|
||||
exponent += gamma2
|
||||
if sim_params.raman_params.order >= 3:
|
||||
z_integrand = expz * (gamma2 + 1/2 * gamma1**2)
|
||||
z_integral = cumsum((z_integrand[:, :-1] + z_integrand[:, 1:]) / 2 * dz, 1)
|
||||
gamma3 = zeros(gamma1.shape)
|
||||
gamma3[:, 1:] = sum(crpz[:, :, 1:] * z_integral, 1)
|
||||
exponent += gamma3
|
||||
if sim_params.raman_params.order >= 4:
|
||||
z_integrand = expz * (gamma3 + gamma1 * gamma2 + 1/factorial(3) * gamma1**3)
|
||||
z_integral = cumsum((z_integrand[:, :-1] + z_integrand[:, 1:]) / 2 * dz, 1)
|
||||
gamma4 = zeros(gamma1.shape)
|
||||
gamma4[:, 1:] = sum(crpz[:, :, 1:] * z_integral, 1)
|
||||
exponent += gamma4
|
||||
power_interval *= exp(exponent)
|
||||
power[:, interval[1:]] = power_interval[:, 1:]
|
||||
power_in = power_interval[:, -1]
|
||||
elif sim_params.raman_params.method == 'numerical':
|
||||
dz = z[1:] - z[:-1]
|
||||
power = outer(power_in, ones(z.size))
|
||||
for i in range(1, z.size):
|
||||
power[:, i] = (power[:, i - 1] * (1 + (- alpha + sum(cr * power[:, i - 1], 1)) * dz[i - 1]) *
|
||||
lumped_losses[i - 1])
|
||||
else:
|
||||
raise ValueError(f'Method {sim_params.raman_params.method} not implemented in Raman Solver.')
|
||||
return power
|
||||
|
||||
@staticmethod
|
||||
def iterative_algorithm(co_initial_guess_power, cnt_initial_guess_power, co_frequency, cnt_frequency, z, fiber,
|
||||
lumped_losses):
|
||||
"""Solves the Raman first order derivative equation in case of both co- and counter-propagating
|
||||
frequencies
|
||||
"""Solves the Raman equation in case of both co- and counter-propagating frequencies
|
||||
|
||||
:param co_initial_guess_power: co-propagationg Raman first order derivative equation solution
|
||||
:param cnt_initial_guess_power: counter-propagationg Raman first order derivative equation solution
|
||||
@@ -276,6 +332,7 @@ class NliSolver:
|
||||
List of implemented methods:
|
||||
'gn_model_analytic': eq. 120 from arXiv:1209.0394
|
||||
'ggn_spectrally_separated': eq. 21 from arXiv: 1710.02225
|
||||
'ggn_approx': eq. 24-25 jlt:9741324
|
||||
"""
|
||||
|
||||
SPM_WEIGHT = (16.0 / 27.0)
|
||||
@@ -324,6 +381,28 @@ class NliSolver:
|
||||
g_nli = sum(g_nli, 1)
|
||||
g_nli = interp(spectral_info.frequency, cut_frequency, g_nli)
|
||||
nli = spectral_info.baud_rate * g_nli # Local white noise
|
||||
elif 'ggn_approx' in sim_params.nli_params.method:
|
||||
if sim_params.nli_params.computed_channels is not None:
|
||||
cut_indices = array(sim_params.nli_params.computed_channels) - 1
|
||||
elif sim_params.nli_params.computed_number_of_channels is not None:
|
||||
nb_ch_computed = sim_params.nli_params.computed_number_of_channels
|
||||
nb_ch = len(spectral_info.channel_number)
|
||||
cut_indices = array([round(i * (nb_ch - 1) / (nb_ch_computed - 1)) for i in range(0, nb_ch_computed)])
|
||||
else:
|
||||
cut_indices = array(spectral_info.channel_number) - 1
|
||||
|
||||
eta = NliSolver._ggn_approx(cut_indices, spectral_info, fiber, srs)
|
||||
|
||||
# Interpolation over the channels not indicated as computed channels in simulation parameters
|
||||
cut_power = outer(spectral_info.signal[cut_indices], ones(spectral_info.number_of_channels))
|
||||
cut_frequency = spectral_info.frequency[cut_indices]
|
||||
pump_power = outer(ones(cut_indices.size), spectral_info.signal)
|
||||
cut_baud_rate = outer(spectral_info.baud_rate[cut_indices], ones(spectral_info.number_of_channels))
|
||||
|
||||
g_nli = eta * cut_power * pump_power ** 2 / cut_baud_rate
|
||||
g_nli = sum(g_nli, 1)
|
||||
g_nli = interp(spectral_info.frequency, cut_frequency, g_nli)
|
||||
nli = spectral_info.baud_rate * g_nli # Local white noise
|
||||
else:
|
||||
raise ValueError(f'Method {sim_params.nli_params.method} not implemented.')
|
||||
|
||||
@@ -526,6 +605,89 @@ class NliSolver:
|
||||
freq_offset_th = ((k_ref * delta_f_ref) * rs_ref * beta2_ref) / (beta2 * symbol_rate)
|
||||
return freq_offset_th
|
||||
|
||||
@staticmethod
|
||||
def _ggn_approx(cut_indices, spectral_info: SpectralInformation, fiber, srs, spm_weight=SPM_WEIGHT,
|
||||
xpm_weight=XPM_WEIGHT):
|
||||
"""Computes the nonlinear interference power evaluated at the fiber input.
|
||||
The method uses eq. 24-25 of https://ieeexplore.ieee.org/document/9741324
|
||||
"""
|
||||
# Spectral Features
|
||||
nch = spectral_info.number_of_channels
|
||||
frequency = spectral_info.frequency
|
||||
baud_rate = spectral_info.baud_rate
|
||||
slot_width = spectral_info.slot_width
|
||||
roll_off = spectral_info.roll_off
|
||||
df = spectral_info.df + diag(full(nch, nan))
|
||||
|
||||
# Physical fiber parameters
|
||||
alpha = fiber.alpha(frequency)
|
||||
beta2 = fiber.beta2(frequency)
|
||||
gamma = outer(fiber.gamma(frequency[cut_indices]), ones(nch))
|
||||
|
||||
identity = diag(ones(nch))
|
||||
weight = spm_weight * identity + xpm_weight * (ones([nch, nch]) - identity)
|
||||
weight = weight[cut_indices, :]
|
||||
|
||||
dispersion_tolerance = sim_params.nli_params.dispersion_tolerance
|
||||
phase_shift_tolerance = sim_params.nli_params.phase_shift_tolerance
|
||||
max_slot_width = max(slot_width)
|
||||
max_beta2 = max(abs(beta2))
|
||||
delta_z = sim_params.raman_params.result_spatial_resolution
|
||||
|
||||
# Approximation psi
|
||||
loss_profile = srs.loss_profile[:nch]
|
||||
z = srs.z
|
||||
psi = NliSolver._approx_psi(df=df, frequency=frequency, beta2=beta2, baud_rate=baud_rate,
|
||||
loss_profile=loss_profile, z=z)
|
||||
|
||||
# GGN for SPM
|
||||
for cut_index in cut_indices:
|
||||
dn = 0
|
||||
cut_frequency = frequency[cut_index]
|
||||
cut_baud_rate = baud_rate[cut_index]
|
||||
cut_roll_off = roll_off[cut_index]
|
||||
cut_beta2 = beta2[cut_index]
|
||||
cut_alpha = alpha[cut_index]
|
||||
k_tol = dispersion_tolerance * abs(cut_alpha)
|
||||
phi_tol = phase_shift_tolerance / delta_z
|
||||
f_cut_resolution = min(k_tol, phi_tol) / abs(max_beta2) / (4 * pi ** 2 * (1 + dn) * max_slot_width)
|
||||
f_pump_resolution = min(k_tol, phi_tol) / abs(max_beta2) / (4 * pi ** 2 * max_slot_width)
|
||||
psi[cut_index, cut_index] = NliSolver._generalized_psi(cut_frequency, cut_frequency, cut_baud_rate,
|
||||
cut_roll_off, cut_frequency, cut_baud_rate,
|
||||
cut_roll_off, f_cut_resolution, f_pump_resolution,
|
||||
srs, cut_alpha, cut_beta2, 0, cut_frequency)
|
||||
psi = psi[cut_indices, :]
|
||||
cut_baud_rate = outer(baud_rate[cut_indices], ones(nch))
|
||||
pump_baud_rate = outer(ones(cut_indices.size), baud_rate)
|
||||
|
||||
eta_cut_central_frequency = \
|
||||
gamma ** 2 * weight * psi / (cut_baud_rate * pump_baud_rate ** 2)
|
||||
eta = cut_baud_rate * eta_cut_central_frequency # Local white noise
|
||||
|
||||
return eta
|
||||
|
||||
@staticmethod
|
||||
def _approx_psi(df, frequency, baud_rate, beta2, loss_profile, z):
|
||||
"""Computes the approximated psi function similarly to the one used in the GN model.
|
||||
The method uses eq. 25 of https://ieeexplore.ieee.org/document/9741324"""
|
||||
pump_baud_rate = outer(ones(frequency.size), baud_rate)
|
||||
cut_beta = outer(beta2, ones(frequency.size))
|
||||
pump_beta = outer(ones(frequency.size), beta2)
|
||||
delta_z = abs(z[:-1] - z[1:])
|
||||
|
||||
loss_lin = log(loss_profile)
|
||||
pump_alpha = (loss_lin[:, 1:] - loss_lin[:, :-1]) / delta_z
|
||||
leff = abs((loss_profile[:, 1:] - loss_profile[:, :-1]) / sqrt(abs(pump_alpha))) * pump_alpha / abs(pump_alpha)
|
||||
leff = reshape(outer(leff, ones(z.size - 1)), newshape=[leff.shape[0], leff.shape[1], leff.shape[1]])
|
||||
leff2 = leff * swapaxes(leff, 2, 1)
|
||||
leff2 = sum(leff2, axis=(1, 2))
|
||||
z_int = outer(ones(frequency.size), leff2)
|
||||
|
||||
delta_beta = (cut_beta + pump_beta) / 2
|
||||
psi = z_int * pump_baud_rate / (4 * pi * abs(delta_beta * df))
|
||||
return psi
|
||||
|
||||
|
||||
|
||||
def estimate_nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
||||
if nf_min < -10:
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.utils: utility functions that are used with gnpy
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.utils
|
||||
===============
|
||||
@@ -12,6 +17,7 @@ from csv import writer
|
||||
from numpy import pi, cos, sqrt, log10, linspace, zeros, shape, where, logical_and, mean, array
|
||||
from scipy import constants
|
||||
from copy import deepcopy
|
||||
from typing import List, Union, Dict
|
||||
|
||||
from gnpy.core.exceptions import ConfigurationError
|
||||
|
||||
@@ -328,6 +334,35 @@ def merge_amplifier_restrictions(dict1, dict2):
|
||||
return copy_dict1
|
||||
|
||||
|
||||
def use_pmd_coef(dict1: dict, dict2: dict):
|
||||
"""If Fiber dict1 is missing the pmd_coef value then use the one of dict2.
|
||||
In addition records in "pmd_coef_defined" key the pmd_coef if is was defined in dict1.
|
||||
|
||||
:param dict1: A dictionnary that contains "pmd_coef" key.
|
||||
:type dict1: dict
|
||||
:param dict2: Another dictionnary that contains "pmd_coef" key.
|
||||
:type dict2: dict
|
||||
|
||||
>>> dict1 = {'a': 1, 'pmd_coef': 1.5e-15}
|
||||
>>> dict2 = {'a': 2, 'pmd_coef': 2e-15}
|
||||
>>> use_pmd_coef(dict1, dict2)
|
||||
>>> dict1
|
||||
{'a': 1, 'pmd_coef': 1.5e-15, 'pmd_coef_defined': True}
|
||||
|
||||
>>> dict1 = {'a': 1}
|
||||
>>> use_pmd_coef(dict1, dict2)
|
||||
>>> dict1
|
||||
{'a': 1, 'pmd_coef_defined': False, 'pmd_coef': 2e-15}
|
||||
"""
|
||||
if 'pmd_coef' in dict1 and not dict1['pmd_coef'] \
|
||||
or ('pmd_coef' not in dict1 and 'pmd_coef' in dict2):
|
||||
dict1['pmd_coef_defined'] = False
|
||||
dict1['pmd_coef'] = dict2['pmd_coef']
|
||||
elif 'pmd_coef' in dict1 and dict1['pmd_coef']:
|
||||
dict1['pmd_coef_defined'] = True
|
||||
# all other case do not need any change
|
||||
|
||||
|
||||
def silent_remove(this_list, elem):
|
||||
"""Remove matching elements from a list without raising ValueError
|
||||
|
||||
@@ -443,6 +478,119 @@ def restore_order(elements, order):
|
||||
return [elements[i[0]] for i in sorted(enumerate(order), key=lambda x:x[1]) if elements[i[0]] is not None]
|
||||
|
||||
|
||||
def unique_ordered(elements):
|
||||
"""
|
||||
"""
|
||||
unique_elements = []
|
||||
for element in elements:
|
||||
if element not in unique_elements:
|
||||
unique_elements.append(element)
|
||||
return unique_elements
|
||||
|
||||
|
||||
def convert_empty_to_none(json_data: Union[list, dict]) -> dict:
|
||||
"""Convert all instances of "a": [None] into "a": None
|
||||
|
||||
:param json_data: the input data.
|
||||
:type json_data: dict
|
||||
:return: the converted data.
|
||||
:rtype: dict
|
||||
|
||||
>>> json_data = {
|
||||
... "uid": "[east edfa in Lannion",
|
||||
... "type_variety": "multiband_booster",
|
||||
... "metadata": {
|
||||
... "location": {
|
||||
... "latitude": 0.000000,
|
||||
... "longitude": 0.000000,
|
||||
... "city": "Zion",
|
||||
... "region": ""
|
||||
... }
|
||||
... },
|
||||
... "type": "Multiband_amplifier",
|
||||
... "amplifiers": [{
|
||||
... "type_variety": "multiband_booster_LOW_C",
|
||||
... "operational": {
|
||||
... "gain_target": 12.22,
|
||||
... "delta_p": 4.19,
|
||||
... "out_voa": [None],
|
||||
... "tilt_target": 0.00,
|
||||
... "f_min": 191.3,
|
||||
... "f_max": 196.1
|
||||
... }
|
||||
... }, {
|
||||
... "type_variety": "multiband_booster_LOW_L",
|
||||
... "operational": {
|
||||
... "gain_target": 12.05,
|
||||
... "delta_p": 4.19,
|
||||
... "out_voa": [None],
|
||||
... "tilt_target": 0.00,
|
||||
... "f_min": 186.1,
|
||||
... "f_max": 190.9
|
||||
... }
|
||||
... }
|
||||
... ]
|
||||
... }
|
||||
>>> convert_empty_to_none(json_data)
|
||||
{'uid': '[east edfa in Lannion', 'type_variety': 'multiband_booster', \
|
||||
'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}}, \
|
||||
'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'multiband_booster_LOW_C', \
|
||||
'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0, \
|
||||
'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'multiband_booster_LOW_L', \
|
||||
'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0, \
|
||||
'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
|
||||
"""
|
||||
if isinstance(json_data, dict):
|
||||
for key, value in json_data.items():
|
||||
json_data[key] = convert_empty_to_none(value)
|
||||
elif isinstance(json_data, list):
|
||||
if len(json_data) == 1 and json_data[0] is None:
|
||||
return None
|
||||
for i, elem in enumerate(json_data):
|
||||
json_data[i] = convert_empty_to_none(elem)
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_none_to_empty(json_data: Union[list, dict]) -> dict:
|
||||
"""Convert all instances of "a": None into "a": [None], to be compliant with RFC7951.
|
||||
|
||||
:param json_data: the input data.
|
||||
:type json_data: dict
|
||||
:return: the converted data.
|
||||
:rtype: dict
|
||||
|
||||
>>> a = {'uid': '[east edfa in Lannion', 'type_variety': 'multiband_booster',
|
||||
... 'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}},
|
||||
... 'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'multiband_booster_LOW_C',
|
||||
... 'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0,
|
||||
... 'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'multiband_booster_LOW_L',
|
||||
... 'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0,
|
||||
... 'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
>>> convert_none_to_empty(a)
|
||||
{'uid': '[east edfa in Lannion', 'type_variety': 'multiband_booster', \
|
||||
'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}}, \
|
||||
'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'multiband_booster_LOW_C', \
|
||||
'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': [None], 'tilt_target': 0.0, \
|
||||
'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'multiband_booster_LOW_L', \
|
||||
'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': [None], 'tilt_target': 0.0, \
|
||||
'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
|
||||
"""
|
||||
if json_data == [None]:
|
||||
# already conformed
|
||||
return json_data
|
||||
if isinstance(json_data, dict):
|
||||
for key, value in json_data.items():
|
||||
json_data[key] = convert_none_to_empty(value)
|
||||
elif isinstance(json_data, list):
|
||||
for i, elem in enumerate(json_data):
|
||||
json_data[i] = convert_none_to_empty(elem)
|
||||
elif json_data is None:
|
||||
return [None]
|
||||
return json_data
|
||||
|
||||
|
||||
def calculate_absolute_min_or_zero(x: array) -> array:
|
||||
"""Calculates the element-wise absolute minimum between the x and zero.
|
||||
|
||||
@@ -458,3 +606,220 @@ def calculate_absolute_min_or_zero(x: array) -> array:
|
||||
array([1., 0., 3.])
|
||||
"""
|
||||
return (abs(x) - x) / 2
|
||||
|
||||
|
||||
def nice_column_str(data: List[List[str]], max_length: int = 30, padding: int = 1) -> str:
|
||||
"""data is a list of rows, creates strings with nice alignment per colum and padding with spaces
|
||||
letf justified
|
||||
|
||||
>>> table_data = [['aaa', 'b', 'c'], ['aaaaaaaa', 'bbb', 'c'], ['a', 'bbbbbbbbbb', 'c']]
|
||||
>>> print(nice_column_str(table_data))
|
||||
aaa b c
|
||||
aaaaaaaa bbb c
|
||||
a bbbbbbbbbb c
|
||||
"""
|
||||
# transpose data to determine size of columns
|
||||
transposed_data = list(map(list, zip(*data)))
|
||||
column_width = [max(len(word) for word in column) + padding for column in transposed_data]
|
||||
nice_str = []
|
||||
for row in data:
|
||||
column = ''.join(word[0:max_length].ljust(min(width, max_length)) for width, word in zip(column_width, row))
|
||||
nice_str.append(f'{column}')
|
||||
return '\n'.join(nice_str)
|
||||
|
||||
|
||||
def filter_valid_amp_bands(amp_bands: List[List[dict]]) -> List[List[dict]]:
|
||||
"""Filter out invalid amplifier bands that lack f_min or f_max.
|
||||
|
||||
:param amp_bands: A list of lists containing amplifier band dictionaries.
|
||||
:type amp_bands: List[List[dict]]
|
||||
:return: A filtered list of amplifier bands that contain valid f_min and f_max.
|
||||
:rtype: List[List[dict]]
|
||||
"""
|
||||
return [amp for amp in amp_bands if all(band.get('f_min') is not None and band.get('f_max') is not None
|
||||
for band in amp)]
|
||||
|
||||
|
||||
def remove_duplicates(amp_bands: List[List[dict]]) -> List[List[dict]]:
|
||||
"""Remove duplicate amplifier bands.
|
||||
|
||||
:param amp_bands: A list of lists containing amplifier band dictionaries.
|
||||
:type amp_bands: List[List[dict]]
|
||||
:return: A list of unique amplifier bands.
|
||||
:rtype: List[List[dict]]
|
||||
"""
|
||||
unique_amp_bands = []
|
||||
for amp in amp_bands:
|
||||
if amp not in unique_amp_bands:
|
||||
unique_amp_bands.append(amp)
|
||||
return unique_amp_bands
|
||||
|
||||
|
||||
def calculate_spacing(first: dict, second: dict, default_spacing: float, default_design_bands: Union[List[Dict], None],
|
||||
f_min: float, f_max: float) -> float:
|
||||
"""Calculate the spacing for the given frequency range.
|
||||
|
||||
:param first: The first amplifier band dictionary.
|
||||
:type first: dict
|
||||
:param second: The second amplifier band dictionary.
|
||||
:type second: dict
|
||||
:param default_spacing: The default spacing to use if no specific spacing can be determined.
|
||||
:type default_spacing: float
|
||||
:param default_design_bands: Optional list of design bands to determine spacing from.
|
||||
:type default_design_bands: Union[List[Dict], None]
|
||||
:param f_min: The minimum frequency of the range.
|
||||
:type f_min: float
|
||||
:param f_max: The maximum frequency of the range.
|
||||
:type f_max: float
|
||||
:return: The calculated spacing for the given frequency range.
|
||||
:rtype: float
|
||||
"""
|
||||
if first.get('spacing') is not None and second.get('spacing') is not None:
|
||||
return max(first['spacing'], second['spacing'])
|
||||
elif first.get('spacing') is not None:
|
||||
return first['spacing']
|
||||
elif second.get('spacing') is not None:
|
||||
return second['spacing']
|
||||
elif default_design_bands:
|
||||
temp = get_spacing_from_band(default_design_bands, f_min, f_max)
|
||||
return temp if temp is not None else default_spacing
|
||||
return default_spacing
|
||||
|
||||
|
||||
def find_common_range(amp_bands: List[List[dict]], default_band_f_min: Union[float, None],
|
||||
default_band_f_max: Union[float, None], default_spacing: float,
|
||||
default_design_bands: Union[List[Dict], None] = None) -> List[dict]:
|
||||
"""
|
||||
Find the common frequency range of amplifier bands.
|
||||
|
||||
If there are no amplifiers in the path, then use the default band parameters.
|
||||
|
||||
:param amp_bands: A list of lists containing amplifier band dictionaries, each with 'f_min', 'f_max',
|
||||
and optionally 'spacing'.
|
||||
:type amp_bands: List[List[dict]]
|
||||
:param default_band_f_min: The minimum frequency of the default band.
|
||||
:type default_band_f_min: Union[float, None]
|
||||
:param default_band_f_max: The maximum frequency of the default band.
|
||||
:type default_band_f_max: Union[float, None]
|
||||
:param default_spacing: The default spacing to use if no specific spacing can be determined.
|
||||
:type default_spacing: float
|
||||
:param default_design_bands: Optional list of design bands to determine spacing from.
|
||||
:type default_design_bands: Union[List[Dict], None]
|
||||
:return: A list of dictionaries representing the common frequency ranges with their respective spacings.
|
||||
:rtype: List[dict]
|
||||
|
||||
>>> amp_bands = [[{'f_min': 191e12, 'f_max' : 195e12, 'spacing': 70e9}, {'f_min': 186e12, 'f_max' : 190e12}], \
|
||||
[{'f_min': 185e12, 'f_max' : 189e12}, {'f_min': 192e12, 'f_max' : 196e12}], \
|
||||
[{'f_min': 186e12, 'f_max': 193e12}]]
|
||||
>>> find_common_range(amp_bands, 190e12, 195e12, 50e9)
|
||||
[{'f_min': 186000000000000.0, 'f_max': 189000000000000.0, 'spacing': 50000000000.0}, \
|
||||
{'f_min': 192000000000000.0, 'f_max': 193000000000000.0, 'spacing': 70000000000.0}]
|
||||
|
||||
>>> amp_bands = [[{'f_min': 191e12, 'f_max' : 195e12}, {'f_min': 186e12, 'f_max' : 190e12}], \
|
||||
[{'f_min': 185e12, 'f_max' : 189e12}, {'f_min': 192e12, 'f_max' : 196e12}], \
|
||||
[{'f_min': 186e12, 'f_max': 192e12}]]
|
||||
>>> find_common_range(amp_bands, 190e12, 195e12, 50e9)
|
||||
[{'f_min': 186000000000000.0, 'f_max': 189000000000000.0, 'spacing': 50000000000.0}]
|
||||
"""
|
||||
# Step 1: Filter and sort amplifier bands
|
||||
_amp_bands = [sorted(amp, key=lambda x: x['f_min']) for amp in filter_valid_amp_bands(amp_bands)]
|
||||
unique_amp_bands = remove_duplicates(_amp_bands)
|
||||
|
||||
# Step 2: Handle cases with no valid bands
|
||||
if unique_amp_bands:
|
||||
common_range = unique_amp_bands[0]
|
||||
else:
|
||||
if default_band_f_min is None or default_band_f_max is None:
|
||||
return []
|
||||
return [{'f_min': default_band_f_min, 'f_max': default_band_f_max, 'spacing': None}]
|
||||
|
||||
# Step 3: Calculate common frequency range
|
||||
for bands in unique_amp_bands:
|
||||
new_common_range = []
|
||||
for first in common_range:
|
||||
for second in bands:
|
||||
f_min = max(first['f_min'], second['f_min'])
|
||||
f_max = min(first['f_max'], second['f_max'])
|
||||
if f_min < f_max:
|
||||
spacing = calculate_spacing(first, second, default_spacing, default_design_bands, f_min, f_max)
|
||||
new_common_range.append({'f_min': f_min, 'f_max': f_max, 'spacing': spacing})
|
||||
|
||||
common_range = new_common_range
|
||||
|
||||
return sorted(common_range, key=lambda x: x['f_min'])
|
||||
|
||||
|
||||
def transform_data(data: str) -> Union[List[int], None]:
|
||||
"""Transforms a float into an list of one integer or a string separated by "|" into a list of integers.
|
||||
|
||||
Args:
|
||||
data (float or str): The data to transform.
|
||||
|
||||
Returns:
|
||||
list of int: The transformed data as a list of integers.
|
||||
|
||||
Examples:
|
||||
>>> transform_data(5.0)
|
||||
[5]
|
||||
|
||||
>>> transform_data('1 | 2 | 3')
|
||||
[1, 2, 3]
|
||||
"""
|
||||
if isinstance(data, float):
|
||||
return [int(data)]
|
||||
if isinstance(data, str):
|
||||
return [int(x) for x in data.split(' | ')]
|
||||
return None
|
||||
|
||||
|
||||
def convert_pmd_lineic(pmd: Union[float, None], length: float, length_unit: str) -> Union[float, None]:
|
||||
"""Convert PMD value of the span in ps into pmd_lineic in s/sqrt(km)
|
||||
|
||||
:param pmd: value in ps
|
||||
:type pmd: Union[float, None]
|
||||
:param length: value in length_unit
|
||||
:type length: float
|
||||
:param length_unit: 'km' or 'm'
|
||||
:type length_unit: str
|
||||
:return: lineic PMD s/sqrt(m)
|
||||
:rtype: Union[float, None]
|
||||
|
||||
>>> convert_pmd_lineic(10, 0.001, 'km')
|
||||
1e-11
|
||||
"""
|
||||
if pmd:
|
||||
return pmd * 1e-12 / sqrt(convert_length(length, length_unit))
|
||||
return None
|
||||
def get_spacing_from_band(design_bands: List[Dict], f_min, f_max):
|
||||
"""Retrieve the spacing for a frequency range based on design bands.
|
||||
|
||||
This function checks if the midpoint of the provided frequency range (f_min, f_max)
|
||||
falls within any of the design bands. If it does, the corresponding spacing is returned.
|
||||
|
||||
:param design_bands: A list of design band dictionaries, each containing 'f_min', 'f_max', and 'spacing'.
|
||||
:type design_bands: List[Dict]
|
||||
:param f_min: The minimum frequency of the range.
|
||||
:type f_min: float
|
||||
:param f_max: The maximum frequency of the range.
|
||||
:type f_max: float
|
||||
:return: The spacing corresponding to the design band that contains the midpoint of the range,
|
||||
or None if no such band exists.
|
||||
:rtype: Union[float, None]
|
||||
"""
|
||||
midpoint = (f_min + f_max) / 2
|
||||
for band in design_bands:
|
||||
if midpoint >= band['f_min'] and midpoint <= band['f_max']:
|
||||
return band['spacing']
|
||||
return None
|
||||
|
||||
|
||||
def reorder_per_degree_design_bands(per_degree_design_bands: dict):
|
||||
"""Sort the design bands for each degree by their minimum frequency (f_min).
|
||||
|
||||
This function modifies the input dictionary in place, sorting the design bands for each unique identifier.
|
||||
|
||||
:param per_degree_design_bands: A dictionary where keys are unique identifiers and values are lists of design band dictionaries.
|
||||
:type per_degree_design_bands: Dict[str, List[Dict]]
|
||||
"""
|
||||
for uid, design_bands in per_degree_design_bands.items():
|
||||
per_degree_design_bands[uid] = sorted(design_bands, key=lambda x: x['f_min'])
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Utility functions that creates an Eqpt sheet template
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
create_eqpt_sheet.py
|
||||
====================
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
{
|
||||
"nf_ripple": [
|
||||
0.0
|
||||
],
|
||||
"gain_ripple": [
|
||||
0.0
|
||||
],
|
||||
"f_min": 191.35e12,
|
||||
"f_max": 196.1e12,
|
||||
"dgt": [
|
||||
1.0,
|
||||
1.017807767853702,
|
||||
1.0356155337864215,
|
||||
1.0534217504465226,
|
||||
1.0712204022764056,
|
||||
1.0895983485572227,
|
||||
1.108555289615659,
|
||||
1.1280891949729075,
|
||||
1.1476135933863398,
|
||||
1.1672278304018044,
|
||||
1.1869318618366975,
|
||||
1.2067249615595257,
|
||||
1.2264996957264114,
|
||||
1.2428104897182262,
|
||||
1.2556591482982988,
|
||||
1.2650555289898042,
|
||||
1.2744470198196236,
|
||||
1.2838336236692311,
|
||||
1.2932153453410835,
|
||||
1.3040618749785347,
|
||||
1.316383926863083,
|
||||
1.3301807335621048,
|
||||
1.3439818461440451,
|
||||
1.3598972673004606,
|
||||
1.3779439775587023,
|
||||
1.3981208704326855,
|
||||
1.418273806730323,
|
||||
1.4340878115214444,
|
||||
1.445565137158368,
|
||||
1.45273959485914,
|
||||
1.4599103316162523,
|
||||
1.4670307626366115,
|
||||
1.474100442252211,
|
||||
1.48111939735681,
|
||||
1.488134243479226,
|
||||
1.495145456062699,
|
||||
1.502153039909686,
|
||||
1.5097346239790443,
|
||||
1.5178910621476225,
|
||||
1.5266220576235803,
|
||||
1.5353620432989845,
|
||||
1.545374152761467,
|
||||
1.5566577309558969,
|
||||
1.569199764184379,
|
||||
1.5817353179379183,
|
||||
1.5986915141218316,
|
||||
1.6201194134191075,
|
||||
1.6460167077689267,
|
||||
1.6719047669939942,
|
||||
1.6918150918099673,
|
||||
1.7057507692361864,
|
||||
1.7137640932265894,
|
||||
1.7217732861435076,
|
||||
1.7297783508684146,
|
||||
1.737780757913635,
|
||||
1.7459181197626403,
|
||||
1.7541903672600494,
|
||||
1.7625959636196327,
|
||||
1.7709972329654864,
|
||||
1.7793941781790852,
|
||||
1.7877868031023945,
|
||||
1.7961751115773796,
|
||||
1.8045606557581335,
|
||||
1.8139629377087627,
|
||||
1.824381436842932,
|
||||
1.835814081380705,
|
||||
1.847275503201129,
|
||||
1.862235672444246,
|
||||
1.8806927939516411,
|
||||
1.9026104247588487,
|
||||
1.9245345552113182,
|
||||
1.9482128147680253,
|
||||
1.9736443063300082,
|
||||
2.0008103857988204,
|
||||
2.0279625371819305,
|
||||
2.055100772005235,
|
||||
2.082225099873648,
|
||||
2.1183028432496016,
|
||||
2.16337565384239,
|
||||
2.2174389328192197,
|
||||
2.271520771371253,
|
||||
2.322373696229342,
|
||||
2.3699990328716107,
|
||||
2.414398437185221,
|
||||
2.4587748041127506,
|
||||
2.499446286796604,
|
||||
2.5364027376452056,
|
||||
2.5696460593920065,
|
||||
2.602860350286428,
|
||||
2.630396440815385,
|
||||
2.6521732021128046,
|
||||
2.6681935771243177,
|
||||
2.6841217449620203,
|
||||
2.6947834587664494,
|
||||
2.705443819238505,
|
||||
2.714526681131686
|
||||
]
|
||||
}
|
||||
@@ -23,7 +23,8 @@
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
"con_out": 0.5,
|
||||
"pmd_coef": 3.0e-15
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# update an existing json file with all the 96ch txt files for a given amplifier type
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
Created on Tue Jan 30 12:32:00 2018
|
||||
|
||||
|
||||
@@ -357,7 +357,8 @@
|
||||
"tx_power_dbm": 0,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"sys_margins": 2
|
||||
"sys_margins": 2,
|
||||
"use_si_channel_count_for_design": true
|
||||
}
|
||||
],
|
||||
"Transceiver": [
|
||||
|
||||
479
gnpy/example-data/eqpt_config_multiband.json
Normal file
479
gnpy/example-data/eqpt_config_multiband.json
Normal file
@@ -0,0 +1,479 @@
|
||||
{
|
||||
"Edfa": [
|
||||
{
|
||||
"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_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_reduced",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"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_def": "fixed_gain",
|
||||
"gain_flatmax": 21,
|
||||
"gain_min": 20,
|
||||
"p_max": 21,
|
||||
"nf0": 5.5,
|
||||
"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
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain_C",
|
||||
"f_min": 191.225e12,
|
||||
"f_max": 196.125e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain_L",
|
||||
"f_min": 186.5e12,
|
||||
"f_max": 190.1e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain",
|
||||
"f_min": 191.25e12,
|
||||
"f_max": 196.15e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 21,
|
||||
"nf_min": 7,
|
||||
"nf_max": 11,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_reduced_band",
|
||||
"f_min": 192.25e12,
|
||||
"f_max": 196.15e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 21,
|
||||
"nf_min": 7,
|
||||
"nf_max": 11,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_bis",
|
||||
"f_min": 191.25e12,
|
||||
"f_max": 196.15e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 21,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_L_ter",
|
||||
"f_min": 186.55e12,
|
||||
"f_max": 190.05e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 16,
|
||||
"nf_min": 7,
|
||||
"nf_max": 11,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_L",
|
||||
"f_min": 186.55e12,
|
||||
"f_max": 190.05e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 21,
|
||||
"nf_min": 7,
|
||||
"nf_max": 11,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_L_reduced_band",
|
||||
"f_min": 187.3e12,
|
||||
"f_max": 190.05e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 21,
|
||||
"nf_min": 7,
|
||||
"nf_max": 11,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "test",
|
||||
"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": true
|
||||
},
|
||||
{
|
||||
"type_variety": "test_fixed_gain",
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 21,
|
||||
"gain_min": 20,
|
||||
"p_max": 21,
|
||||
"nf0": 5,
|
||||
"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
|
||||
},
|
||||
{
|
||||
"type_variety": "std_booster_L",
|
||||
"f_min": 186.55e12,
|
||||
"f_max": 190.05e12,
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 21,
|
||||
"gain_min": 20,
|
||||
"p_max": 21,
|
||||
"nf0": 5,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_booster_multiband",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_booster",
|
||||
"std_booster_L"
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain_multiband",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_medium_gain_C",
|
||||
"std_medium_gain_L"
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_multiband",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_low_gain",
|
||||
"std_low_gain_L"
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_multiband_ter",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_low_gain",
|
||||
"std_low_gain_L_ter"
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_multiband_bis",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_low_gain_bis",
|
||||
"std_low_gain_L"
|
||||
],
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_multiband_reduced",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_low_gain_reduced",
|
||||
"std_low_gain_L"
|
||||
],
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain_multiband_reduced_bis",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_low_gain_bis",
|
||||
"std_low_gain_L_reduced_band"
|
||||
],
|
||||
"allowed_for_design": true
|
||||
}
|
||||
],
|
||||
"Fiber": [
|
||||
{
|
||||
"type_variety": "SSMF",
|
||||
"dispersion": 1.67e-05,
|
||||
"effective_area": 83e-12,
|
||||
"pmd_coef": 1.265e-15
|
||||
},
|
||||
{
|
||||
"type_variety": "NZDF",
|
||||
"dispersion": 0.5e-05,
|
||||
"effective_area": 72e-12,
|
||||
"pmd_coef": 1.265e-15
|
||||
},
|
||||
{
|
||||
"type_variety": "LOF",
|
||||
"dispersion": 2.2e-05,
|
||||
"effective_area": 125e-12,
|
||||
"pmd_coef": 1.265e-15
|
||||
}
|
||||
],
|
||||
"RamanFiber": [
|
||||
{
|
||||
"type_variety": "SSMF",
|
||||
"dispersion": 1.67e-05,
|
||||
"effective_area": 83e-12,
|
||||
"pmd_coef": 1.265e-15
|
||||
}
|
||||
],
|
||||
"Span": [
|
||||
{
|
||||
"power_mode": true,
|
||||
"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": -20,
|
||||
"add_drop_osnr": 38,
|
||||
"pmd": 0,
|
||||
"pdl": 0,
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"SI": [
|
||||
{
|
||||
"f_min": 191.3e12,
|
||||
"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
|
||||
},
|
||||
{
|
||||
"type_variety": "lband",
|
||||
"f_min": 186.3e12,
|
||||
"baud_rate": 32e9,
|
||||
"f_max": 190.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": "vendorA_trx-type1",
|
||||
"frequency": {
|
||||
"min": 191.35e12,
|
||||
"max": 196.1e12
|
||||
},
|
||||
"mode": [
|
||||
{
|
||||
"format": "mode 1",
|
||||
"baud_rate": 32e9,
|
||||
"OSNR": 11,
|
||||
"bit_rate": 100e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost": 1
|
||||
},
|
||||
{
|
||||
"format": "mode 2",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"format": "mode 3",
|
||||
"baud_rate": 44e9,
|
||||
"OSNR": 18,
|
||||
"bit_rate": 300e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 62.5e9,
|
||||
"cost": 1
|
||||
},
|
||||
{
|
||||
"format": "mode 2",
|
||||
"baud_rate": 66e9,
|
||||
"OSNR": 21,
|
||||
"bit_rate": 400e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost": 1
|
||||
},
|
||||
{
|
||||
"format": "mode 4",
|
||||
"baud_rate": 66e9,
|
||||
"OSNR": 16,
|
||||
"bit_rate": 200e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
74
gnpy/example-data/extra_eqpt_config.json
Normal file
74
gnpy/example-data/extra_eqpt_config.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"Edfa": [
|
||||
{
|
||||
"type_variety": "user_defined",
|
||||
"type_def": "variable_gain",
|
||||
"f_min": 192.0e12,
|
||||
"f_max": 195.9e12,
|
||||
"gain_flatmax": 25,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"default_config_from_json": "user_edfa_config.json",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
}, {
|
||||
"type_variety": "user_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
|
||||
}
|
||||
],
|
||||
"Transceiver": [
|
||||
{
|
||||
"type_variety": "ZR400G",
|
||||
"frequency": {
|
||||
"min": 191.3e12,
|
||||
"max": 196.1e12
|
||||
},
|
||||
"mode": [
|
||||
{
|
||||
"format": "SFF-ID:70",
|
||||
"baud_rate": 60138546798,
|
||||
"OSNR": 24,
|
||||
"bit_rate": 400e9,
|
||||
"roll_off": 0.2,
|
||||
"tx_osnr": 34,
|
||||
"min_spacing": 75e9,
|
||||
"penalties": [
|
||||
{
|
||||
"chromatic_dispersion": 20e3,
|
||||
"penalty_value": 0.5
|
||||
},
|
||||
{
|
||||
"chromatic_dispersion": 0,
|
||||
"penalty_value": 0
|
||||
},
|
||||
{
|
||||
"pmd": 20,
|
||||
"penalty_value": 0.5
|
||||
},
|
||||
{
|
||||
"pdl": 1.5,
|
||||
"penalty_value": 0
|
||||
},
|
||||
{
|
||||
"pdl": 3.5,
|
||||
"penalty_value": 1.8
|
||||
},
|
||||
{
|
||||
"pdl": 3,
|
||||
"penalty_value": 1.3
|
||||
}
|
||||
],
|
||||
"cost": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -52,8 +52,8 @@
|
||||
"explicit-route-objects": {
|
||||
"route-object-include-exclude": [
|
||||
{
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"index": 0,
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"num-unnum-hop": {
|
||||
"node-id": "roadm Brest_KLA",
|
||||
"link-tp-id": "link-tp-id is not used",
|
||||
@@ -61,8 +61,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"index": 1,
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"num-unnum-hop": {
|
||||
"node-id": "roadm Lannion_CAS",
|
||||
"link-tp-id": "link-tp-id is not used",
|
||||
@@ -70,8 +70,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"index": 2,
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"num-unnum-hop": {
|
||||
"node-id": "roadm Lorient_KMA",
|
||||
"link-tp-id": "link-tp-id is not used",
|
||||
@@ -79,8 +79,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"index": 3,
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"num-unnum-hop": {
|
||||
"node-id": "roadm Vannes_KBE",
|
||||
"link-tp-id": "link-tp-id is not used",
|
||||
|
||||
1894
gnpy/example-data/multiband_example_network.json
Normal file
1894
gnpy/example-data/multiband_example_network.json
Normal file
File diff suppressed because it is too large
Load Diff
24
gnpy/example-data/multiband_spectrum.json
Normal file
24
gnpy/example-data/multiband_spectrum.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"spectrum": [
|
||||
{
|
||||
"f_min": 191.25e12,
|
||||
"baud_rate": 32e9,
|
||||
"f_max": 195.1e12,
|
||||
"slot_width": 50e9,
|
||||
"delta_pdb": 0,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"label": "cband"
|
||||
},
|
||||
{
|
||||
"f_min": 186.3e12,
|
||||
"baud_rate": 32e9,
|
||||
"f_max": 190.1e12,
|
||||
"slot_width": 50e9,
|
||||
"delta_pdb": 0,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"label": "lband"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -32,7 +32,6 @@
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 80.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
|
||||
22
gnpy/example-data/service_pluggable.json
Normal file
22
gnpy/example-data/service_pluggable.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"path-request": [
|
||||
{
|
||||
"request-id": "0",
|
||||
"source": "trx Brest_KLA",
|
||||
"destination": "trx Lannion_CAS",
|
||||
"src-tp-id": "trx Brest_KLA",
|
||||
"dst-tp-id": "trx Lannion_CAS",
|
||||
"bidirectional": false,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "ZR400G",
|
||||
"trx_mode": "SFF-ID:70",
|
||||
"spacing": 100000000000.0,
|
||||
"tx_power": 0.0015,
|
||||
"path_bandwidth": 400000000000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
0.0359549,
|
||||
5.82851
|
||||
],
|
||||
"f_min": 191.35e12,
|
||||
"f_max": 196.1e12,
|
||||
"f_min": 191.275e12,
|
||||
"f_max": 196.125e12,
|
||||
"nf_ripple": [
|
||||
0.4372876328262819,
|
||||
0.4372876328262819,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.tools.cli_examples: Common code for CLI examples
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.tools.cli_examples
|
||||
=======================
|
||||
@@ -11,28 +16,28 @@ Common code for CLI examples
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
from math import ceil
|
||||
from numpy import linspace, mean
|
||||
from pathlib import Path
|
||||
from typing import Union, List
|
||||
from math import ceil
|
||||
from numpy import mean
|
||||
|
||||
import gnpy.core.ansi_escapes as ansi_escapes
|
||||
from gnpy.core import ansi_escapes
|
||||
from gnpy.core.elements import Transceiver, Fiber, RamanFiber
|
||||
from gnpy.core.equipment import trx_mode_params
|
||||
import gnpy.core.exceptions as exceptions
|
||||
from gnpy.core.network import add_missing_elements_in_network, design_network
|
||||
from gnpy.core import exceptions
|
||||
from gnpy.core.parameters import SimParams
|
||||
from gnpy.core.utils import db2lin, lin2db, automatic_nch, watt2dbm, dbm2watt
|
||||
from gnpy.topology.request import (ResultElement, jsontocsv, compute_path_dsjctn, requests_aggregation,
|
||||
BLOCKING_NOPATH, correct_json_route_list,
|
||||
deduplicate_disjunctions, compute_path_with_disjunction,
|
||||
PathRequest, compute_constrained_path, propagate)
|
||||
from gnpy.topology.spectrum_assignment import build_oms_list, pth_assign_spectrum
|
||||
from gnpy.tools.json_io import (load_equipment, load_network, load_json, load_requests, save_network,
|
||||
requests_from_json, disjunctions_from_json, save_json, load_initial_spectrum)
|
||||
from gnpy.core.utils import lin2db, pretty_summary_print, per_label_average, watt2dbm
|
||||
from gnpy.topology.request import (ResultElement, jsontocsv, BLOCKING_NOPATH)
|
||||
from gnpy.tools.json_io import (load_equipments_and_configs, load_network, load_json, load_requests, save_network,
|
||||
requests_from_json, save_json, load_initial_spectrum, DEFAULT_EQPT_CONFIG)
|
||||
from gnpy.tools.plots import plot_baseline, plot_results
|
||||
from gnpy.tools.worker_utils import designed_network, transmission_simulation, planning
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_examples_dir = Path(__file__).parent.parent / 'example-data'
|
||||
_default_config_files = ['example-data/std_medium_gain_advanced_config.json',
|
||||
'example-data/Juniper-BoosterHG.json',
|
||||
'parameters.DEFAULT_EDFA_CONFIG']
|
||||
_help_footer = '''
|
||||
This program is part of GNPy, https://github.com/TelecomInfraProject/oopt-gnpy
|
||||
|
||||
@@ -44,14 +49,35 @@ _help_fname_json_csv = 'FILE.(json|csv)'
|
||||
|
||||
|
||||
def show_example_data_dir():
|
||||
"""Print the example data directory path."""
|
||||
print(f'{_examples_dir}/')
|
||||
|
||||
|
||||
def load_common_data(equipment_filename, topology_filename, simulation_filename, save_raw_network_filename):
|
||||
"""Load common configuration from JSON files"""
|
||||
def load_common_data(equipment_filename: Path,
|
||||
extra_equipment_filenames: List[Path], extra_config_filenames: List[Path],
|
||||
topology_filename: Path, simulation_filename: Path, save_raw_network_filename: Path):
|
||||
"""Load common configuration from JSON files, merging additional equipment if provided.
|
||||
|
||||
:param equipment_filename: Path to the main equipment configuration file.
|
||||
:type equipment_filename: Path
|
||||
:param extra_equipment_filenames: List of additional equipment configuration files.
|
||||
:type extra_equipment_filenames: List[Path]
|
||||
:param extra_config_filenames: List of additional configuration files.
|
||||
:type extra_config_filenames: List[Path]
|
||||
:param topology_filename: Path to the network topology file.
|
||||
:type topology_filename: Path
|
||||
:param simulation_filename: Path to the simulation parameters file.
|
||||
:type simulation_filename: Path
|
||||
:param save_raw_network_filename: Path to save the raw network configuration.
|
||||
:type save_raw_network_filename: Path
|
||||
:raises exceptions.EquipmentConfigError: If there is a configuration error in the equipment library.
|
||||
:raises exceptions.NetworkTopologyError: If the network definition is invalid.
|
||||
:raises exceptions.ParametersError: If there is an error with simulation parameters.
|
||||
:raises exceptions.ConfigurationError: If there is a general configuration error.
|
||||
:raises exceptions.ServiceError: If there is a service-related error.
|
||||
"""
|
||||
try:
|
||||
equipment = load_equipment(equipment_filename)
|
||||
equipment = load_equipments_and_configs(equipment_filename, extra_equipment_filenames, extra_config_filenames)
|
||||
network = load_network(topology_filename, equipment)
|
||||
if save_raw_network_filename is not None:
|
||||
save_network(network, save_raw_network_filename)
|
||||
@@ -84,18 +110,30 @@ def load_common_data(equipment_filename, topology_filename, simulation_filename,
|
||||
return (equipment, network)
|
||||
|
||||
|
||||
def _setup_logging(args):
|
||||
def _setup_logging(args: argparse.Namespace):
|
||||
"""Set up logging based on verbosity level.
|
||||
|
||||
:param args: The parsed command-line arguments.
|
||||
:type args: argparse.Namespace
|
||||
"""
|
||||
logging.basicConfig(level={2: logging.DEBUG, 1: logging.INFO, 0: logging.WARNING}.get(args.verbose, logging.DEBUG))
|
||||
|
||||
|
||||
def _add_common_options(parser: argparse.ArgumentParser, network_default: Path):
|
||||
"""Add common command-line options to the argument parser.
|
||||
|
||||
:param parser: The argument parser to which options will be added.
|
||||
:type parser: argparse.ArgumentParser
|
||||
:param network_default: The default path for the network topology file.
|
||||
:type network_default: Path
|
||||
"""
|
||||
parser.add_argument('topology', nargs='?', type=Path, metavar='NETWORK-TOPOLOGY.(json|xls|xlsx)',
|
||||
default=network_default,
|
||||
help='Input network topology')
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0,
|
||||
help='Increase verbosity (can be specified several times)')
|
||||
parser.add_argument('-e', '--equipment', type=Path, metavar=_help_fname_json,
|
||||
default=_examples_dir / 'eqpt_config.json', help='Equipment library')
|
||||
default=DEFAULT_EQPT_CONFIG, help='Equipment library')
|
||||
parser.add_argument('--sim-params', type=Path, metavar=_help_fname_json,
|
||||
default=None, help='Path to the JSON containing simulation parameters (required for Raman). '
|
||||
f'Example: {_examples_dir / "sim_params.json"}')
|
||||
@@ -106,14 +144,30 @@ def _add_common_options(parser: argparse.ArgumentParser, network_default: Path):
|
||||
parser.add_argument('--no-insert-edfas', action='store_true',
|
||||
help='Disable insertion of EDFAs after ROADMs and fibers '
|
||||
'as well as splitting of fibers by auto-design.')
|
||||
# Option for additional equipment files
|
||||
parser.add_argument('--extra-equipment', nargs='+', type=Path,
|
||||
metavar=_help_fname_json, default=None,
|
||||
help='List of additional equipment files to complement the main equipment file.')
|
||||
# Option for additional config files
|
||||
parser.add_argument('--extra-config', nargs='+', type=Path,
|
||||
metavar=_help_fname_json,
|
||||
help='List of additional config files as referenced in equipment files with '
|
||||
'"advanced_config_from_json" or "default_config_from_json".'
|
||||
f'Existing configs:\n{_default_config_files}')
|
||||
|
||||
|
||||
def transmission_main_example(args=None):
|
||||
def transmission_main_example(args: Union[List[str], None] = None):
|
||||
"""Main script running a single simulation. It returns the detailed power across crossed elements and
|
||||
average performance accross all channels.
|
||||
|
||||
:param args: Command-line arguments (default is None).
|
||||
:type args: Union[List[str], None]
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Send a full spectrum load through the network from point A to point B',
|
||||
epilog=_help_footer,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
)
|
||||
_add_common_options(parser, network_default=_examples_dir / 'edfa_example_network.json')
|
||||
parser.add_argument('--show-channels', action='store_true', help='Show final per-channel OSNR and GSNR summary')
|
||||
parser.add_argument('-pl', '--plot', action='store_true')
|
||||
@@ -126,7 +180,8 @@ def transmission_main_example(args=None):
|
||||
args = parser.parse_args(args if args is not None else sys.argv[1:])
|
||||
_setup_logging(args)
|
||||
|
||||
(equipment, network) = load_common_data(args.equipment, args.topology, args.sim_params, args.save_network_before_autodesign)
|
||||
(equipment, network) = load_common_data(args.equipment, args.extra_equipment, args.extra_config, args.topology,
|
||||
args.sim_params, args.save_network_before_autodesign)
|
||||
|
||||
if args.plot:
|
||||
plot_baseline(network)
|
||||
@@ -144,19 +199,17 @@ def transmission_main_example(args=None):
|
||||
sys.exit()
|
||||
|
||||
# First try to find exact match if source/destination provided
|
||||
source = None
|
||||
if args.source:
|
||||
source = transceivers.pop(args.source, None)
|
||||
valid_source = True if source else False
|
||||
else:
|
||||
source = None
|
||||
_logger.info('No source node specified: picking random transceiver')
|
||||
valid_source = bool(source)
|
||||
|
||||
destination = None
|
||||
nodes_list = []
|
||||
loose_list = []
|
||||
if args.destination:
|
||||
destination = transceivers.pop(args.destination, None)
|
||||
valid_destination = True if destination else False
|
||||
else:
|
||||
destination = None
|
||||
_logger.info('No destination node specified: picking random transceiver')
|
||||
valid_destination = bool(destination)
|
||||
|
||||
# If no exact match try to find partial match
|
||||
if args.source and not source:
|
||||
@@ -173,112 +226,77 @@ def transmission_main_example(args=None):
|
||||
if not source:
|
||||
source = list(transceivers.values())[0]
|
||||
del transceivers[source.uid]
|
||||
_logger.info('No source node specified: picking random transceiver')
|
||||
|
||||
if not destination:
|
||||
destination = list(transceivers.values())[0]
|
||||
nodes_list = [destination.uid]
|
||||
loose_list = ['STRICT']
|
||||
_logger.info('No destination node specified: picking random transceiver')
|
||||
|
||||
_logger.info(f'source = {args.source!r}')
|
||||
_logger.info(f'destination = {args.destination!r}')
|
||||
_logger.info(f'source = {source.uid!r}')
|
||||
_logger.info(f'destination = {destination.uid!r}')
|
||||
|
||||
params = {}
|
||||
params['request_id'] = 0
|
||||
params['trx_type'] = ''
|
||||
params['trx_mode'] = ''
|
||||
params['source'] = source.uid
|
||||
params['destination'] = destination.uid
|
||||
params['bidir'] = False
|
||||
params['nodes_list'] = [destination.uid]
|
||||
params['loose_list'] = ['strict']
|
||||
params['format'] = ''
|
||||
params['path_bandwidth'] = 0
|
||||
params['effective_freq_slot'] = None
|
||||
trx_params = trx_mode_params(equipment)
|
||||
trx_params['power'] = dbm2watt(equipment['SI']['default'].power_dbm)
|
||||
trx_params['tx_power'] = dbm2watt(equipment['SI']['default'].power_dbm)
|
||||
if args.power:
|
||||
trx_params['power'] = dbm2watt(float(args.power))
|
||||
trx_params['tx_power'] = dbm2watt(float(args.power))
|
||||
params.update(trx_params)
|
||||
initial_spectrum = None
|
||||
params['nb_channel'] = automatic_nch(trx_params['f_min'], trx_params['f_max'], trx_params['spacing'])
|
||||
# use ref_req to hold reference channel used for design and req for the propagation
|
||||
# and req to hold channels to be propagated
|
||||
# apply power sweep on the design and on the channels
|
||||
ref_req = PathRequest(**params)
|
||||
pref_ch_db = watt2dbm(ref_req.power)
|
||||
if args.spectrum:
|
||||
# use the spectrum defined by user for the propagation.
|
||||
# the nb of channel for design remains the one of the reference channel
|
||||
initial_spectrum = load_initial_spectrum(args.spectrum)
|
||||
params['nb_channel'] = len(initial_spectrum)
|
||||
print('User input for spectrum used for propagation instead of SI')
|
||||
req = PathRequest(**params)
|
||||
p_ch_db = watt2dbm(req.power)
|
||||
req.initial_spectrum = initial_spectrum
|
||||
print(f'There are {req.nb_channel} channels propagating')
|
||||
power_mode = equipment['Span']['default'].power_mode
|
||||
print('\n'.join([f'Power mode is set to {power_mode}',
|
||||
'=> it can be modified in eqpt_config.json - Span']))
|
||||
if not args.no_insert_edfas:
|
||||
try:
|
||||
add_missing_elements_in_network(network, equipment)
|
||||
except exceptions.NetworkTopologyError as e:
|
||||
print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
except exceptions.ConfigurationError as e:
|
||||
print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
|
||||
path = compute_constrained_path(network, req)
|
||||
spans = [s.params.length for s in path if isinstance(s, RamanFiber) or isinstance(s, Fiber)]
|
||||
power_range = [0]
|
||||
if power_mode:
|
||||
# power cannot be changed in gain mode
|
||||
try:
|
||||
p_start, p_stop, p_step = equipment['SI']['default'].power_range_db
|
||||
p_num = abs(int(round((p_stop - p_start) / p_step))) + 1 if p_step != 0 else 1
|
||||
power_range = list(linspace(p_start, p_stop, p_num))
|
||||
except TypeError:
|
||||
print('invalid power range definition in eqpt_config, should be power_range_db: [lower, upper, step]')
|
||||
# initial network is designed using req.power. that is that any missing information (amp gain or delta_p) is filled
|
||||
# using this req.power, previous to any sweep requested later on.
|
||||
# Simulate !
|
||||
try:
|
||||
design_network(ref_req, network, equipment, set_connector_losses=True, verbose=True)
|
||||
network, req, ref_req = designed_network(equipment, network, source.uid, destination.uid,
|
||||
nodes_list=nodes_list, loose_list=loose_list,
|
||||
args_power=args.power,
|
||||
initial_spectrum=initial_spectrum,
|
||||
no_insert_edfas=args.no_insert_edfas)
|
||||
path, propagations_for_path, powers_dbm, infos = transmission_simulation(equipment, network, req, ref_req)
|
||||
except exceptions.NetworkTopologyError as e:
|
||||
print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
except exceptions.ConfigurationError as e:
|
||||
print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
|
||||
print(f'\nThere are {len(spans)} fiber spans over {sum(spans)/1000:.0f} km between {source.uid} '
|
||||
except exceptions.ServiceError as e:
|
||||
print(f'Service error: {e}')
|
||||
sys.exit(1)
|
||||
except ValueError:
|
||||
sys.exit(1)
|
||||
# print or export results
|
||||
spans = [s.params.length for s in path if isinstance(s, (Fiber, RamanFiber))]
|
||||
print(f'\nThere are {len(spans)} fiber spans over {sum(spans) / 1000:.0f} km between {source.uid} '
|
||||
f'and {destination.uid}')
|
||||
print(f'\nNow propagating between {source.uid} and {destination.uid}:')
|
||||
for dp_db in power_range:
|
||||
ref_req.power = dbm2watt(pref_ch_db + dp_db)
|
||||
req.power = dbm2watt(p_ch_db + dp_db)
|
||||
design_network(ref_req, network, equipment, set_connector_losses=False, verbose=False)
|
||||
# if initial spectrum did not contain any power, now we need to use this one.
|
||||
# note the initial power defines a differential wrt req.power so that if req.power is set to 2mW (3dBm)
|
||||
# and initial spectrum was set to 0, this sets a initial per channel delta power to -3dB, so that
|
||||
# whatever the equalization, -3 dB is applied on all channels (ie initial power in initial spectrum pre-empts
|
||||
# "--power" option)
|
||||
print(f'Reference used for design: (Input optical power reference in span = {watt2dbm(ref_req.power):.2f}dBm,\n'
|
||||
+ f' spacing = {ref_req.spacing * 1e-9:.2f}GHz\n'
|
||||
+ f' nb_channels = {ref_req.nb_channel})')
|
||||
print('\nChannels propagating: (Input optical power deviation in span = '
|
||||
+ f'{pretty_summary_print(per_label_average(infos.delta_pdb_per_channel, infos.label))}dB,\n'
|
||||
+ ' spacing = '
|
||||
+ f'{pretty_summary_print(per_label_average(infos.slot_width * 1e-9, infos.label))}GHz,\n'
|
||||
+ ' transceiver output power = '
|
||||
+ f'{pretty_summary_print(per_label_average(watt2dbm(infos.tx_power), infos.label))}dBm,\n'
|
||||
+ f' nb_channels = {infos.number_of_channels})')
|
||||
for mypath, power_dbm in zip(propagations_for_path, powers_dbm):
|
||||
if power_mode:
|
||||
print(f'\nPropagating with input power = {ansi_escapes.cyan}{watt2dbm(req.power):.2f} '
|
||||
print(f'Input optical power reference in span = {ansi_escapes.cyan}{power_dbm:.2f} '
|
||||
+ f'dBm{ansi_escapes.reset}:')
|
||||
else:
|
||||
print(f'\nPropagating in {ansi_escapes.cyan}gain mode{ansi_escapes.reset}: power cannot be set manually')
|
||||
infos = propagate(path, req, equipment)
|
||||
if len(power_range) == 1:
|
||||
for elem in path:
|
||||
print('\nPropagating in {ansi_escapes.cyan}gain mode{ansi_escapes.reset}: power cannot be set manually')
|
||||
if len(powers_dbm) == 1:
|
||||
for elem in mypath:
|
||||
print(elem)
|
||||
if power_mode:
|
||||
print(f'\nTransmission result for input power = {lin2db(req.power*1e3):.2f} dBm:')
|
||||
print(f'\nTransmission result for input optical power reference in span = {power_dbm:.2f} dBm:')
|
||||
else:
|
||||
print(f'\nTransmission results:')
|
||||
print('\nTransmission results:')
|
||||
print(f' Final GSNR (0.1 nm): {ansi_escapes.cyan}{mean(destination.snr_01nm):.02f} dB{ansi_escapes.reset}')
|
||||
else:
|
||||
print(path[-1])
|
||||
print(mypath[-1])
|
||||
|
||||
if args.save_network is not None:
|
||||
save_network(network, args.save_network)
|
||||
@@ -326,11 +344,17 @@ def _path_result_json(pathresult):
|
||||
|
||||
|
||||
def path_requests_run(args=None):
|
||||
"""Main script running several services simulations. It returns a summary of the average performance
|
||||
for each service.
|
||||
|
||||
:param args: Command-line arguments (default is None).
|
||||
:type args: Union[List[str], None]
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Compute performance for a list of services provided in a json file or an excel sheet',
|
||||
epilog=_help_footer,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
)
|
||||
_add_common_options(parser, network_default=_examples_dir / 'meshTopologyExampleV2.xls')
|
||||
parser.add_argument('service_filename', nargs='?', type=Path, metavar='SERVICES-REQUESTS.(json|xls|xlsx)',
|
||||
default=_examples_dir / 'meshTopologyExampleV2.xls',
|
||||
@@ -339,111 +363,49 @@ def path_requests_run(args=None):
|
||||
help='considers that all demands are bidir')
|
||||
parser.add_argument('-o', '--output', type=Path, metavar=_help_fname_json_csv,
|
||||
help='Store satisifed requests into a JSON or CSV file')
|
||||
parser.add_argument('--redesign-per-request', action='store_true', help='Redesign the network at each request'
|
||||
+ ' computation using the request as the reference channel')
|
||||
|
||||
args = parser.parse_args(args if args is not None else sys.argv[1:])
|
||||
_setup_logging(args)
|
||||
|
||||
_logger.info(f'Computing path requests {args.service_filename.name} into JSON format')
|
||||
|
||||
(equipment, network) = load_common_data(args.equipment, args.topology, args.sim_params, args.save_network_before_autodesign)
|
||||
(equipment, network) = \
|
||||
load_common_data(args.equipment, args.extra_equipment, args.extra_config, args.topology, args.sim_params,
|
||||
args.save_network_before_autodesign)
|
||||
|
||||
# Build the network once using the default power defined in SI in eqpt config
|
||||
# TODO power density: db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by
|
||||
# spacing, f_min and f_max
|
||||
if not args.no_insert_edfas:
|
||||
try:
|
||||
add_missing_elements_in_network(network, equipment)
|
||||
except exceptions.NetworkTopologyError as e:
|
||||
print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
except exceptions.ConfigurationError as e:
|
||||
print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
|
||||
params = {
|
||||
'request_id': 'reference',
|
||||
'trx_type': '',
|
||||
'trx_mode': '',
|
||||
'source': None,
|
||||
'destination': None,
|
||||
'bidir': False,
|
||||
'nodes_list': [],
|
||||
'loose_list': [],
|
||||
'format': '',
|
||||
'path_bandwidth': 0,
|
||||
'effective_freq_slot': None,
|
||||
'nb_channel': automatic_nch(equipment['SI']['default'].f_min, equipment['SI']['default'].f_max,
|
||||
equipment['SI']['default'].spacing),
|
||||
'power': dbm2watt(equipment['SI']['default'].power_dbm),
|
||||
'tx_power': dbm2watt(equipment['SI']['default'].power_dbm)
|
||||
}
|
||||
trx_params = trx_mode_params(equipment)
|
||||
params.update(trx_params)
|
||||
reference_channel = PathRequest(**params)
|
||||
try:
|
||||
design_network(reference_channel, network, equipment, verbose=True)
|
||||
network, _, _ = designed_network(equipment, network, no_insert_edfas=args.no_insert_edfas)
|
||||
data = load_requests(args.service_filename, equipment, bidir=args.bidir,
|
||||
network=network, network_filename=args.topology)
|
||||
_data = requests_from_json(data, equipment)
|
||||
_, propagatedpths, reversed_propagatedpths, rqs, dsjn, result = \
|
||||
planning(network, equipment, data, redesign=args.redesign_per_request)
|
||||
except exceptions.NetworkTopologyError as e:
|
||||
print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
except exceptions.ConfigurationError as e:
|
||||
print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
|
||||
if args.save_network is not None:
|
||||
save_network(network, args.save_network)
|
||||
print(f'{ansi_escapes.blue}Network (after autodesign) saved to {args.save_network}{ansi_escapes.reset}')
|
||||
oms_list = build_oms_list(network, equipment)
|
||||
|
||||
try:
|
||||
data = load_requests(args.service_filename, equipment, bidir=args.bidir,
|
||||
network=network, network_filename=args.topology)
|
||||
rqs = requests_from_json(data, equipment)
|
||||
except exceptions.ServiceError as e:
|
||||
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {e}')
|
||||
sys.exit(1)
|
||||
# check that request ids are unique. Non unique ids, may
|
||||
# mess the computation: better to stop the computation
|
||||
all_ids = [r.request_id for r in rqs]
|
||||
if len(all_ids) != len(set(all_ids)):
|
||||
for item in list(set(all_ids)):
|
||||
all_ids.remove(item)
|
||||
msg = f'Requests id {all_ids} are not unique'
|
||||
_logger.critical(msg)
|
||||
sys.exit()
|
||||
rqs = correct_json_route_list(network, rqs)
|
||||
|
||||
# pths = compute_path(network, equipment, rqs)
|
||||
dsjn = disjunctions_from_json(data)
|
||||
|
||||
print(f'{ansi_escapes.blue}List of disjunctions{ansi_escapes.reset}')
|
||||
print(dsjn)
|
||||
# need to warn or correct in case of wrong disjunction form
|
||||
# disjunction must not be repeated with same or different ids
|
||||
dsjn = deduplicate_disjunctions(dsjn)
|
||||
|
||||
# Aggregate demands with same exact constraints
|
||||
print(f'{ansi_escapes.blue}Aggregating similar requests{ansi_escapes.reset}')
|
||||
|
||||
rqs, dsjn = requests_aggregation(rqs, dsjn)
|
||||
# TODO export novel set of aggregated demands in a json file
|
||||
|
||||
print(f'{ansi_escapes.blue}The following services have been requested:{ansi_escapes.reset}')
|
||||
print(rqs)
|
||||
|
||||
print(f'{ansi_escapes.blue}Computing all paths with constraints{ansi_escapes.reset}')
|
||||
try:
|
||||
pths = compute_path_dsjctn(network, equipment, rqs, dsjn)
|
||||
except exceptions.DisjunctionError as this_e:
|
||||
print(f'{ansi_escapes.red}Disjunction error:{ansi_escapes.reset} {this_e}')
|
||||
sys.exit(1)
|
||||
except exceptions.ServiceError as e:
|
||||
print(f'Service error: {e}')
|
||||
sys.exit(1)
|
||||
except ValueError:
|
||||
sys.exit(1)
|
||||
print(f'{ansi_escapes.blue}List of disjunctions{ansi_escapes.reset}')
|
||||
print(dsjn)
|
||||
print(f'{ansi_escapes.blue}The following services have been requested:{ansi_escapes.reset}')
|
||||
print(_data)
|
||||
|
||||
print(f'{ansi_escapes.blue}Propagating on selected path{ansi_escapes.reset}')
|
||||
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)
|
||||
if args.save_network is not None:
|
||||
save_network(network, args.save_network)
|
||||
print(f'Network (after autodesign) saved to {args.save_network}')
|
||||
|
||||
print(f'{ansi_escapes.blue}Result summary{ansi_escapes.reset}')
|
||||
header = ['req id', ' demand', ' GSNR@bandwidth A-Z (Z-A)', ' GSNR@0.1nm A-Z (Z-A)',
|
||||
@@ -454,27 +416,27 @@ def path_requests_run(args=None):
|
||||
for i, this_p in enumerate(propagatedpths):
|
||||
rev_pth = reversed_propagatedpths[i]
|
||||
if rev_pth and this_p:
|
||||
psnrb = f'{round(mean(this_p[-1].snr),2)} ({round(mean(rev_pth[-1].snr),2)})'
|
||||
psnrb = f'{round(mean(this_p[-1].snr), 2)} ({round(mean(rev_pth[-1].snr), 2)})'
|
||||
psnr = f'{round(mean(this_p[-1].snr_01nm), 2)}' +\
|
||||
f' ({round(mean(rev_pth[-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)}'
|
||||
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}']
|
||||
'-', '-', '-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9, 2)}',
|
||||
'-', '{rqs[i].blocking_reason}']
|
||||
else:
|
||||
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}']
|
||||
psnr, '-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9, 2)}',
|
||||
'-', 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 + equipment["SI"]["default"].sys_margins}',
|
||||
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})']
|
||||
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)
|
||||
|
||||
col_width = max(len(word) for row in data for word in row[2:]) # padding
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
243
gnpy/tools/convert_legacy_yang.py
Normal file
243
gnpy/tools/convert_legacy_yang.py
Normal file
@@ -0,0 +1,243 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# JSON files format conversion legacy <-> YANG
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
YANG formatted to legacy format conversion
|
||||
==========================================
|
||||
|
||||
"""
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from pathlib import Path
|
||||
from copy import deepcopy
|
||||
import json
|
||||
from typing import Dict
|
||||
|
||||
from gnpy.tools.yang_convert_utils import convert_degree, convert_back_degree, \
|
||||
convert_delta_power_range, convert_back_delta_power_range, \
|
||||
convert_dict, convert_back, \
|
||||
remove_null_region_city, remove_union_that_fail, \
|
||||
convert_design_band, convert_back_design_band, \
|
||||
convert_none_to_empty, convert_empty_to_none, \
|
||||
convert_loss_coeff_list, convert_back_loss_coeff_list, \
|
||||
ELEMENTS_KEY, PATH_REQUEST_KEY, RESPONSE_KEY, SPECTRUM_KEY, EQPT_TYPES, EDFA_CONFIG_KEYS, SIM_PARAMS_KEYS, \
|
||||
TOPO_NMSP, SERV_NMSP, EQPT_NMSP, SPECTRUM_NMSP, SIM_PARAMS_NMSP, EDFA_CONFIG_NMSP, RESP_NMSP, \
|
||||
dump_data, add_missing_default_type_variety, \
|
||||
remove_namespace_context, load_data, reorder_route_objects, reorder_lumped_losses_objects, \
|
||||
reorder_raman_pumps, convert_raman_coef, convert_back_raman_coef, convert_raman_efficiency, \
|
||||
convert_back_raman_efficiency, convert_nf_coef, convert_back_nf_coef, \
|
||||
convert_nf_fit_coef, convert_back_nf_fit_coef
|
||||
|
||||
|
||||
def legacy_to_yang(json_data: Dict) -> Dict:
|
||||
"""Convert legacy format to GNPy YANG format.
|
||||
|
||||
This function adds the required namespace if not present and processes the input JSON data
|
||||
based on its structure to convert it to the appropriate YANG format. There is no validation
|
||||
of yang formatted data.
|
||||
|
||||
:param json_data: The input JSON data to convert.
|
||||
:type json_data: Dict
|
||||
:return: The converted JSON data in GNPy YANG format.
|
||||
:rtype: Dict
|
||||
"""
|
||||
json_data = convert_none_to_empty(deepcopy(json_data))
|
||||
|
||||
# case of topology json
|
||||
if ELEMENTS_KEY in json_data:
|
||||
json_data = reorder_raman_pumps(json_data)
|
||||
json_data = reorder_lumped_losses_objects(json_data)
|
||||
json_data = remove_null_region_city(json_data)
|
||||
json_data = convert_degree(json_data)
|
||||
json_data = convert_design_band(json_data)
|
||||
json_data = convert_loss_coeff_list(json_data)
|
||||
json_data = convert_raman_coef(json_data)
|
||||
json_data = {TOPO_NMSP: json_data}
|
||||
elif TOPO_NMSP in json_data:
|
||||
# then this is a new format topology json, ensure that there are no issues
|
||||
json_data[TOPO_NMSP] = convert_degree(json_data[TOPO_NMSP])
|
||||
json_data[TOPO_NMSP] = convert_design_band(json_data[TOPO_NMSP])
|
||||
json_data[TOPO_NMSP] = convert_loss_coeff_list(json_data[TOPO_NMSP])
|
||||
json_data[TOPO_NMSP] = remove_null_region_city(json_data[TOPO_NMSP])
|
||||
|
||||
# case of equipment json
|
||||
elif any(k in json_data for k in EQPT_TYPES):
|
||||
json_data = convert_raman_efficiency(json_data)
|
||||
json_data = convert_delta_power_range(json_data)
|
||||
json_data = convert_nf_coef(json_data)
|
||||
json_data = add_missing_default_type_variety(json_data)
|
||||
json_data = {EQPT_NMSP: json_data}
|
||||
elif EQPT_NMSP in json_data:
|
||||
# then this is already a new format topology json, ensure that there are no issues
|
||||
json_data[EQPT_NMSP] = convert_raman_efficiency(json_data[EQPT_NMSP])
|
||||
json_data[EQPT_NMSP] = convert_delta_power_range(json_data[EQPT_NMSP])
|
||||
json_data[EQPT_NMSP] = convert_nf_coef(json_data[EQPT_NMSP])
|
||||
json_data[EQPT_NMSP] = add_missing_default_type_variety(json_data[EQPT_NMSP])
|
||||
|
||||
# case of service json
|
||||
elif PATH_REQUEST_KEY in json_data:
|
||||
json_data = reorder_route_objects(json_data)
|
||||
json_data = remove_union_that_fail(json_data)
|
||||
json_data = {SERV_NMSP: json_data}
|
||||
|
||||
elif SERV_NMSP in json_data:
|
||||
json_data[SERV_NMSP] = reorder_route_objects(json_data[SERV_NMSP])
|
||||
json_data[SERV_NMSP] = remove_union_that_fail(json_data[SERV_NMSP])
|
||||
|
||||
# case of edfa_config json
|
||||
elif any(k in json_data for k in EDFA_CONFIG_KEYS):
|
||||
json_data = convert_nf_fit_coef(json_data)
|
||||
json_data = {EDFA_CONFIG_NMSP: json_data}
|
||||
|
||||
elif EDFA_CONFIG_NMSP in json_data:
|
||||
json_data[EDFA_CONFIG_NMSP] = convert_nf_fit_coef(json_data[EDFA_CONFIG_NMSP])
|
||||
|
||||
# case of spectrum json
|
||||
elif SPECTRUM_KEY in json_data:
|
||||
json_data = {SPECTRUM_NMSP: json_data[SPECTRUM_KEY]}
|
||||
|
||||
# case of sim_params json
|
||||
elif any(k in json_data for k in SIM_PARAMS_KEYS):
|
||||
json_data = {SIM_PARAMS_NMSP: json_data}
|
||||
|
||||
# case of response json
|
||||
elif RESPONSE_KEY in json_data:
|
||||
json_data = {RESP_NMSP: json_data}
|
||||
|
||||
elif any(k in json_data for k in [SPECTRUM_NMSP, SIM_PARAMS_NMSP, RESP_NMSP]):
|
||||
# then this is a new format json, nothing to convert
|
||||
pass
|
||||
|
||||
else:
|
||||
raise ValueError('Unrecognized type of content (not topology, service or equipment)')
|
||||
|
||||
json_data = convert_dict(json_data)
|
||||
return json_data
|
||||
|
||||
|
||||
def yang_to_legacy(json_data: Dict) -> Dict:
|
||||
"""Convert GNPy YANG format to legacy format.
|
||||
|
||||
This function processes the input JSON data to convert it from the new GNPy YANG format
|
||||
back to the legacy format. It handles various types of content, including topology,
|
||||
equipment, and service jsons, ensuring that the necessary conversions are applied.
|
||||
The input data is validated with oopt-gnpy-libyang.
|
||||
|
||||
:param json_data: The input JSON data in GNPy YANG format to convert.
|
||||
:type json_data: Dict
|
||||
:return: The converted JSON data in legacy format.
|
||||
:rtype: Dict
|
||||
|
||||
:raises ValueError: If the input JSON data does not match any recognized content type
|
||||
(not topology, service, or equipment).
|
||||
"""
|
||||
# validate data compliance: make sure that this is yang formated data before validation.
|
||||
load_data(json.dumps(legacy_to_yang(json_data)))
|
||||
json_data = convert_empty_to_none(json_data)
|
||||
json_data = convert_back(json_data)
|
||||
|
||||
# case of topology json
|
||||
if ELEMENTS_KEY in json_data:
|
||||
json_data = convert_back_degree(json_data)
|
||||
json_data = convert_back_design_band(json_data)
|
||||
json_data = convert_back_loss_coeff_list(json_data)
|
||||
json_data = convert_back_raman_coef(json_data)
|
||||
elif TOPO_NMSP in json_data:
|
||||
json_data = convert_back_degree(json_data[TOPO_NMSP])
|
||||
json_data = convert_back_design_band(json_data)
|
||||
json_data = convert_back_loss_coeff_list(json_data)
|
||||
json_data = convert_back_raman_coef(json_data)
|
||||
|
||||
# case of equipment json
|
||||
elif any(k in json_data for k in EQPT_TYPES):
|
||||
json_data = convert_back_delta_power_range(json_data)
|
||||
json_data = convert_back_raman_efficiency(json_data)
|
||||
json_data = convert_back_nf_coef(json_data)
|
||||
json_data = remove_namespace_context(json_data, "gnpy-eqpt-config:")
|
||||
elif EQPT_NMSP in json_data:
|
||||
json_data[EQPT_NMSP] = convert_back_delta_power_range(json_data[EQPT_NMSP])
|
||||
json_data[EQPT_NMSP] = convert_back_raman_efficiency(json_data[EQPT_NMSP])
|
||||
json_data[EQPT_NMSP] = convert_back_nf_coef(json_data[EQPT_NMSP])
|
||||
json_data = remove_namespace_context(json_data[EQPT_NMSP], "gnpy-eqpt-config:")
|
||||
|
||||
# case of EDFA config json
|
||||
elif any(k in json_data for k in EDFA_CONFIG_KEYS):
|
||||
json_data = convert_back_nf_fit_coef(json_data)
|
||||
elif EDFA_CONFIG_NMSP in json_data:
|
||||
json_data[EDFA_CONFIG_NMSP] = convert_back_nf_fit_coef(json_data[EDFA_CONFIG_NMSP])
|
||||
|
||||
# case of service json
|
||||
elif SERV_NMSP in json_data:
|
||||
json_data = json_data[SERV_NMSP]
|
||||
|
||||
# case of sim_params json
|
||||
elif SIM_PARAMS_NMSP in json_data:
|
||||
json_data = json_data[SIM_PARAMS_NMSP]
|
||||
|
||||
# case of spectrum json
|
||||
elif SPECTRUM_NMSP in json_data:
|
||||
json_data = {SPECTRUM_KEY: json_data[SPECTRUM_NMSP]}
|
||||
|
||||
# case of planning response json
|
||||
elif RESP_NMSP in json_data:
|
||||
json_data = json_data[RESP_NMSP]
|
||||
elif any(k in json_data for k in SIM_PARAMS_KEYS + [SPECTRUM_KEY, RESPONSE_KEY, PATH_REQUEST_KEY]):
|
||||
# then this is a legacy format json, nothing to convert
|
||||
pass
|
||||
else:
|
||||
raise ValueError('Unrecognized type of content (not topology, service or equipment)')
|
||||
return json_data
|
||||
|
||||
|
||||
def main():
|
||||
"""Conversion function
|
||||
"""
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('--legacy-to-yang', nargs='?', type=Path,
|
||||
help='convert file with this name into yangconformedname.json')
|
||||
parser.add_argument('--yang-to-legacy', nargs='?', type=Path,
|
||||
help='convert file with this name into gnpy'
|
||||
+ ' using decimal instead of strings and null instead of [null]')
|
||||
parser.add_argument('--validate', nargs='?', type=Path,
|
||||
help='validate yang conformity')
|
||||
parser.add_argument('-o', '--output', type=Path,
|
||||
help='Stores into file with this name; default = GNPy_legacy_formatted-<file_name>.json or'
|
||||
+ 'GNPy_yang_formatted-<file_name>.json')
|
||||
args = parser.parse_args()
|
||||
|
||||
if not (args.legacy_to_yang or args.yang_to_legacy or args.validate):
|
||||
parser.error("You must specify at least one of --legacy-to-yang, --yang-to-legacy, or --validate ")
|
||||
|
||||
output = None
|
||||
converted = None
|
||||
if args.validate:
|
||||
with open(args.validate, 'r', encoding='utf-8') as f:
|
||||
json_data = json.load(f)
|
||||
load_data(json.dumps(json_data))
|
||||
return 0
|
||||
elif args.legacy_to_yang:
|
||||
prefix = 'GNPy_yang_formatted-'
|
||||
with open(args.legacy_to_yang, 'r', encoding='utf-8') as f:
|
||||
json_data = json.load(f)
|
||||
# note that dump_data automatically validate date against yang models
|
||||
converted = dump_data(legacy_to_yang(json_data))
|
||||
output = prefix + str(args.legacy_to_yang.name)
|
||||
elif args.yang_to_legacy:
|
||||
prefix = 'GNPy_legacy_formatted-'
|
||||
with open(args.yang_to_legacy, 'r', encoding='utf-8') as f:
|
||||
json_data = json.load(f)
|
||||
converted = json.dumps(yang_to_legacy(json_data), indent=2, ensure_ascii=False)
|
||||
output = prefix + str(args.yang_to_legacy.name)
|
||||
if args.output:
|
||||
output = args.output
|
||||
with open(output, 'w', encoding='utf-8') as f:
|
||||
f.write(converted)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
149
gnpy/tools/create_eqpt_sheet.py
Normal file
149
gnpy/tools/create_eqpt_sheet.py
Normal file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Utility functions that creates an Eqpt sheet template
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
create_eqpt_sheet.py
|
||||
====================
|
||||
|
||||
XLS parser that can be called to create a "City" column in the "Eqpt" sheet.
|
||||
|
||||
If not present in the "Nodes" sheet, the "Type" column will be implicitly
|
||||
determined based on the topology.
|
||||
"""
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from pathlib import Path
|
||||
import csv
|
||||
from typing import List, Dict, Optional
|
||||
from logging import getLogger
|
||||
import dataclasses
|
||||
|
||||
from gnpy.core.exceptions import NetworkTopologyError
|
||||
from gnpy.tools.xls_utils import generic_open_workbook, get_sheet, XLS_EXCEPTIONS, all_rows, fast_get_sheet_rows, \
|
||||
WorkbookType, SheetType
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
EXAMPLE_DATA_DIR = Path(__file__).parent.parent / 'example-data'
|
||||
|
||||
PARSER = ArgumentParser()
|
||||
PARSER.add_argument('workbook', type=Path, nargs='?', default=f'{EXAMPLE_DATA_DIR}/meshTopologyExampleV2.xls',
|
||||
help='create the mandatory columns in Eqpt sheet')
|
||||
PARSER.add_argument('-o', '--output', type=Path, help='Store CSV file')
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Node:
|
||||
"""Represents a network node with a unique identifier, connected nodes, and equipment type.
|
||||
|
||||
:param uid: Unique identifier of the node.
|
||||
:type uid: str
|
||||
:param to_node: List of connected node identifiers.
|
||||
:type to_node: List[str.]
|
||||
:param eqpt: Equipment type associated with the node (ROADM, ILA, FUSED).
|
||||
:type eqpt: str
|
||||
"""
|
||||
def __init__(self, uid: str, to_node: List[str], eqpt: str = None):
|
||||
self.uid = uid
|
||||
self.to_node = to_node
|
||||
self.eqpt = eqpt
|
||||
|
||||
|
||||
def open_sheet_with_error_handling(wb: WorkbookType, sheet_name: str, is_xlsx: bool) -> SheetType:
|
||||
"""Opens a sheet from the workbook with error handling.
|
||||
|
||||
:param wb: The opened workbook.
|
||||
:type wb: WorkbookType
|
||||
:param sheet_name: Name of the sheet to open.
|
||||
:type sheet_name: str
|
||||
:param is_xlsx: Boolean indicating if the file is XLSX format.
|
||||
:type is_xlsx: bool
|
||||
:return: The worksheet object.
|
||||
:rtype: SheetType
|
||||
:raises NetworkTopologyError: If the sheet is not found.
|
||||
"""
|
||||
try:
|
||||
sheet = get_sheet(wb, sheet_name, is_xlsx)
|
||||
return sheet
|
||||
except XLS_EXCEPTIONS as exc:
|
||||
msg = f'Error: no {sheet_name} sheet in the file.'
|
||||
raise NetworkTopologyError(msg) from exc
|
||||
|
||||
|
||||
def read_excel(input_filename: Path) -> Dict[str, Node]:
|
||||
"""Reads the 'Nodes' and 'Links' sheets from an Excel file to build a network graph.
|
||||
|
||||
:param input_filename: Path to the Excel file.
|
||||
:type input_filename: Path
|
||||
:return: Dictionary of nodes with their connectivity and equipment type.
|
||||
:rtype: Dict[str, Node]
|
||||
"""
|
||||
wobo, is_xlsx = generic_open_workbook(input_filename)
|
||||
links_sheet = open_sheet_with_error_handling(wobo, 'Links', is_xlsx)
|
||||
get_rows_links = fast_get_sheet_rows(links_sheet) if is_xlsx else None
|
||||
|
||||
nodes = {}
|
||||
for row in all_rows(links_sheet, is_xlsx, start=5, get_rows=get_rows_links):
|
||||
node_a, node_z = row[0].value, row[1].value
|
||||
# Add connection in both directions
|
||||
for node1, node2 in [(node_a, node_z), (node_z, node_a)]:
|
||||
if node1 in nodes:
|
||||
nodes[node1].to_node.append(node2)
|
||||
else:
|
||||
nodes[node1] = Node(node1, [node2])
|
||||
|
||||
nodes_sheet = open_sheet_with_error_handling(wobo, 'Nodes', is_xlsx)
|
||||
get_rows_nodes = fast_get_sheet_rows(nodes_sheet) if is_xlsx else None
|
||||
|
||||
for row in all_rows(nodes_sheet, is_xlsx, start=5, get_rows=get_rows_nodes):
|
||||
node = row[0].value
|
||||
eqpt = row[6].value
|
||||
if node not in nodes:
|
||||
raise NetworkTopologyError(f'Error: node {node} is not listed on the links sheet.')
|
||||
if eqpt == 'ILA' and len(nodes[node].to_node) != 2:
|
||||
degree = len(nodes[node].to_node)
|
||||
raise NetworkTopologyError(f'Error: node {node} has an incompatible node degree ({degree}) '
|
||||
+ 'for its equipment type (ILA).')
|
||||
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
|
||||
return nodes
|
||||
|
||||
|
||||
def create_eqpt_template(nodes: Dict[str, Node], input_filename: Path, output_filename: Optional[Path] = None):
|
||||
"""Creates a CSV template to help users populate equipment types for nodes.
|
||||
|
||||
:param nodes: Dictionary of nodes.
|
||||
:type nodes: Dict[str, Node]
|
||||
:param input_filename: Path to the original Excel file.
|
||||
:type input_filename: Path
|
||||
:param output_filename: Path to save the CSV file; generated if None.
|
||||
:type output_filename: Optional(Path)
|
||||
"""
|
||||
if output_filename is None:
|
||||
output_filename = input_filename.parent / (input_filename.with_suffix('').stem + '_eqpt_sheet.csv')
|
||||
with open(output_filename, mode='w', encoding='utf-8', newline='') as output_file:
|
||||
output_writer = csv.writer(output_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
|
||||
amp_header = ['amp_type', 'att_in', 'amp_gain', 'tilt', 'att_out', 'delta_p']
|
||||
output_writer.writerow(['node_a', 'node_z'] + amp_header + amp_header)
|
||||
for node in nodes.values():
|
||||
if node.eqpt == 'ILA':
|
||||
output_writer.writerow([node.uid, node.to_node[0]])
|
||||
if node.eqpt == 'ROADM':
|
||||
for to_node in node.to_node:
|
||||
output_writer.writerow([node.uid, to_node])
|
||||
msg = f'File {output_filename} successfully created.'
|
||||
logger.info(msg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ARGS = PARSER.parse_args()
|
||||
create_eqpt_template(read_excel(ARGS.workbook), ARGS.workbook, ARGS.output)
|
||||
72
gnpy/tools/default_edfa_config.py
Normal file
72
gnpy/tools/default_edfa_config.py
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.tools.default_edfa_configs: loads JSON configuration files at module initialization time
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.tools.default_edfa_config
|
||||
==============================
|
||||
|
||||
Default configs for pre defined amplifiers:
|
||||
- Juniper-BoosterHG.json,
|
||||
- std_medium_gain_advanced_config.json
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from typing import Dict, Optional
|
||||
from json import JSONDecodeError, load
|
||||
from pathlib import Path
|
||||
|
||||
from gnpy.core.exceptions import ConfigurationError
|
||||
from gnpy.tools.convert_legacy_yang import yang_to_legacy
|
||||
|
||||
|
||||
_logger = getLogger(__name__)
|
||||
_examples_dir = Path(__file__).parent.parent / 'example-data'
|
||||
|
||||
|
||||
def _load_json_file(file_path: Path) -> Optional[Dict]:
|
||||
"""Load and parse a JSON file.
|
||||
:param file_path: Path to the JSON file to load
|
||||
:type file_path: Path
|
||||
:return: Dict containing the parsed JSON data or None if loading fails
|
||||
:rtype: Optional[Dict]
|
||||
"""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
return yang_to_legacy(load(file))
|
||||
except FileNotFoundError:
|
||||
msg = f"Configuration file not found: {file_path}"
|
||||
_logger.error(msg)
|
||||
return None
|
||||
except JSONDecodeError as e:
|
||||
msg = f"Invalid JSON in configuration file {file_path}: {e}"
|
||||
_logger.error(msg)
|
||||
return None
|
||||
|
||||
|
||||
# Default files to load
|
||||
_files_to_load = {
|
||||
"std_medium_gain_advanced_config.json": _examples_dir / "std_medium_gain_advanced_config.json",
|
||||
"Juniper-BoosterHG.json": _examples_dir / "Juniper-BoosterHG.json"
|
||||
}
|
||||
|
||||
# Load configurations
|
||||
_configs: Dict = {}
|
||||
|
||||
for key, filepath in _files_to_load.items():
|
||||
config_data = _load_json_file(filepath)
|
||||
if config_data is not None:
|
||||
_configs[key] = config_data
|
||||
else:
|
||||
_msg = f"Failed to load configuration: {key}. Using empty dict as fallback."
|
||||
_logger.error(_msg)
|
||||
raise ConfigurationError
|
||||
|
||||
# Expose the constant
|
||||
DEFAULT_EXTRA_CONFIG: Dict[str, Dict] = _configs
|
||||
|
||||
DEFAULT_EQPT_CONFIG: Path = _examples_dir / "eqpt_config.json"
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.tools.json_io: Loading and saving data from JSON files in GNPy's internal data format
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.tools.json_io
|
||||
==================
|
||||
@@ -8,24 +13,29 @@ gnpy.tools.json_io
|
||||
Loading and saving data from JSON files in GNPy's internal data format
|
||||
"""
|
||||
|
||||
from networkx import DiGraph
|
||||
from logging import getLogger
|
||||
from pathlib import Path
|
||||
import json
|
||||
from collections import namedtuple
|
||||
from copy import deepcopy
|
||||
from typing import Union, Dict, List, Tuple, Optional
|
||||
from networkx import DiGraph
|
||||
from numpy import arange
|
||||
|
||||
|
||||
from gnpy.core import elements
|
||||
from gnpy.core.equipment import trx_mode_params
|
||||
from gnpy.core.equipment import trx_mode_params, find_type_variety
|
||||
from gnpy.core.exceptions import ConfigurationError, EquipmentConfigError, NetworkTopologyError, ServiceError
|
||||
from gnpy.core.science_utils import estimate_nf_model
|
||||
from gnpy.core.info import Carrier
|
||||
from gnpy.core.utils import automatic_nch, automatic_fmax, merge_amplifier_restrictions, dbm2watt
|
||||
from gnpy.core.parameters import DEFAULT_RAMAN_COEFFICIENT, EdfaParams
|
||||
from gnpy.topology.request import PathRequest, Disjunction, compute_spectrum_slot_vs_bandwidth
|
||||
from gnpy.core.utils import automatic_nch, automatic_fmax, merge_amplifier_restrictions, dbm2watt, use_pmd_coef
|
||||
from gnpy.core.parameters import DEFAULT_RAMAN_COEFFICIENT, EdfaParams, MultiBandParams, DEFAULT_EDFA_CONFIG
|
||||
from gnpy.topology.request import PathRequest, Disjunction, compute_spectrum_slot_vs_bandwidth, ResultElement
|
||||
from gnpy.topology.spectrum_assignment import mvalue_to_slots
|
||||
from gnpy.tools.convert import xls_to_json_data
|
||||
from gnpy.tools.service_sheet import read_service_sheet
|
||||
from gnpy.tools.convert_legacy_yang import yang_to_legacy, legacy_to_yang
|
||||
from gnpy.tools.default_edfa_config import DEFAULT_EXTRA_CONFIG, DEFAULT_EQPT_CONFIG
|
||||
|
||||
|
||||
_logger = getLogger(__name__)
|
||||
@@ -39,19 +49,27 @@ Model_dual_stage = namedtuple('Model_dual_stage', 'preamp_variety booster_variet
|
||||
|
||||
|
||||
class Model_openroadm_preamp:
|
||||
pass
|
||||
"""class to hold nf model specific to OpenROADM preamp
|
||||
"""
|
||||
|
||||
|
||||
class Model_openroadm_booster:
|
||||
pass
|
||||
"""class to hold nf model specific to OpenROADM booster
|
||||
"""
|
||||
|
||||
|
||||
class _JsonThing:
|
||||
"""Base class for json equipment
|
||||
"""
|
||||
def update_attr(self, default_values, kwargs, name):
|
||||
"""Build the attributes based on kwargs dict
|
||||
"""
|
||||
clean_kwargs = {k: v for k, v in kwargs.items() if v != ''}
|
||||
for k, v in default_values.items():
|
||||
setattr(self, k, clean_kwargs.get(k, v))
|
||||
if k not in clean_kwargs and name != 'Amp' and v is not None and v != []:
|
||||
disable_warning_keys = ['use_si_channel_count_for_design', 'voa_step', 'voa_margin', 'span_loss_ref',
|
||||
'power_slope']
|
||||
if k not in clean_kwargs and name != 'Amp' and v is not None and v != [] and k not in disable_warning_keys:
|
||||
# do not show this warning if the default value is None
|
||||
msg = f'\n\tWARNING missing {k} attribute in eqpt_config.json[{name}]' \
|
||||
+ f'\n\tdefault value is {k} = {v}\n'
|
||||
@@ -59,6 +77,8 @@ class _JsonThing:
|
||||
|
||||
|
||||
class SI(_JsonThing):
|
||||
"""Spectrum Information
|
||||
"""
|
||||
default_values = {
|
||||
"f_min": 191.35e12,
|
||||
"f_max": 196.1e12,
|
||||
@@ -69,7 +89,8 @@ class SI(_JsonThing):
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 45,
|
||||
"sys_margins": 0,
|
||||
"tx_power_dbm": None # optional value in SI
|
||||
"tx_power_dbm": None, # optional value in SI
|
||||
"use_si_channel_count_for_design": False # optional value in SI
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
@@ -77,6 +98,8 @@ class SI(_JsonThing):
|
||||
|
||||
|
||||
class Span(_JsonThing):
|
||||
"""Span simulations definition
|
||||
"""
|
||||
default_values = {
|
||||
'power_mode': True,
|
||||
'delta_power_range_db': None,
|
||||
@@ -88,7 +111,11 @@ class Span(_JsonThing):
|
||||
'padding': 10,
|
||||
'EOL': 0,
|
||||
'con_in': 0,
|
||||
'con_out': 0
|
||||
'con_out': 0,
|
||||
"span_loss_ref": 20.0,
|
||||
"power_slope": 0.3,
|
||||
"voa_margin": 1,
|
||||
"voa_step": 0.5
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
@@ -96,6 +123,8 @@ class Span(_JsonThing):
|
||||
|
||||
|
||||
class Roadm(_JsonThing):
|
||||
"""List of ROADM and their specs
|
||||
"""
|
||||
default_values = {
|
||||
'type_variety': 'default',
|
||||
'add_drop_osnr': 100,
|
||||
@@ -128,6 +157,8 @@ class Roadm(_JsonThing):
|
||||
|
||||
|
||||
class Transceiver(_JsonThing):
|
||||
"""List of transceivers and their modes
|
||||
"""
|
||||
default_values = {
|
||||
'type_variety': None,
|
||||
'frequency': None,
|
||||
@@ -160,6 +191,8 @@ class Transceiver(_JsonThing):
|
||||
|
||||
|
||||
class Fiber(_JsonThing):
|
||||
"""Fiber default settings
|
||||
"""
|
||||
default_values = {
|
||||
'type_variety': '',
|
||||
'dispersion': None,
|
||||
@@ -180,30 +213,42 @@ class Fiber(_JsonThing):
|
||||
|
||||
|
||||
class RamanFiber(Fiber):
|
||||
pass
|
||||
"""Raman Fiber default settings
|
||||
"""
|
||||
|
||||
|
||||
class Amp(_JsonThing):
|
||||
"""List of amplifiers with their specs
|
||||
"""
|
||||
default_values = EdfaParams.default_values
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.update_attr(self.default_values, kwargs, 'Amp')
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, filename, **kwargs):
|
||||
config = Path(filename).parent / 'default_edfa_config.json'
|
||||
|
||||
def from_json(cls, extra_configs, **kwargs):
|
||||
"""
|
||||
"""
|
||||
# default EDFA DGT and ripples are defined in parameters DEFAULT_EDFA_CONFIG. copy these values when
|
||||
# creating a new amplifier
|
||||
config = {k: v for k, v in DEFAULT_EDFA_CONFIG.items()}
|
||||
config_filename = 'default' # default value to display in case of error
|
||||
type_variety = kwargs['type_variety']
|
||||
type_def = kwargs.get('type_def', 'variable_gain') # default compatibility with older json eqpt files
|
||||
nf_def = None
|
||||
dual_stage_def = None
|
||||
amplifiers = None
|
||||
|
||||
if type_def == 'fixed_gain':
|
||||
if 'default_config_from_json' in kwargs:
|
||||
# use user defined default instead of DEFAULT_EDFA_CONFIG
|
||||
config_filename = kwargs.pop('default_config_from_json')
|
||||
config = deepcopy(extra_configs[config_filename])
|
||||
try:
|
||||
nf0 = kwargs.pop('nf0')
|
||||
except KeyError: # nf0 is expected for a fixed gain amp
|
||||
except KeyError as exc: # nf0 is expected for a fixed gain amp
|
||||
msg = f'missing nf0 value input for amplifier: {type_variety} in equipment config'
|
||||
raise EquipmentConfigError(msg)
|
||||
raise EquipmentConfigError(msg) from exc
|
||||
for k in ('nf_min', 'nf_max'):
|
||||
try:
|
||||
del kwargs[k]
|
||||
@@ -211,15 +256,21 @@ class Amp(_JsonThing):
|
||||
pass
|
||||
nf_def = Model_fg(nf0)
|
||||
elif type_def == 'advanced_model':
|
||||
config = Path(filename).parent / kwargs.pop('advanced_config_from_json')
|
||||
# use the user file name define in library instead of default config
|
||||
config_filename = kwargs.pop('advanced_config_from_json')
|
||||
config = deepcopy(extra_configs[config_filename])
|
||||
elif type_def == 'variable_gain':
|
||||
if 'default_config_from_json' in kwargs:
|
||||
# use user defined default instead of DEFAULT_EDFA_CONFIG
|
||||
config_filename = kwargs.pop('default_config_from_json')
|
||||
config = deepcopy(extra_configs[config_filename])
|
||||
gain_min, gain_max = kwargs['gain_min'], kwargs['gain_flatmax']
|
||||
try: # nf_min and nf_max are expected for a variable gain amp
|
||||
nf_min = kwargs.pop('nf_min')
|
||||
nf_max = kwargs.pop('nf_max')
|
||||
except KeyError:
|
||||
except KeyError as exc:
|
||||
msg = f'missing nf_min or nf_max value input for amplifier: {type_variety} in equipment config'
|
||||
raise EquipmentConfigError(msg)
|
||||
raise EquipmentConfigError(msg) from exc
|
||||
try: # remove all remaining nf inputs
|
||||
del kwargs['nf0']
|
||||
except KeyError:
|
||||
@@ -229,8 +280,8 @@ class Amp(_JsonThing):
|
||||
elif type_def == 'openroadm':
|
||||
try:
|
||||
nf_coef = kwargs.pop('nf_coef')
|
||||
except KeyError: # nf_coef is expected for openroadm amp
|
||||
raise EquipmentConfigError(f'missing nf_coef input for amplifier: {type_variety} in equipment config')
|
||||
except KeyError as exc: # nf_coef is expected for openroadm amp
|
||||
raise EquipmentConfigError(f'missing nf_coef input for amplifier: {type_variety} in equipment config') from exc
|
||||
nf_def = Model_openroadm_ila(nf_coef)
|
||||
elif type_def == 'openroadm_preamp':
|
||||
nf_def = Model_openroadm_preamp()
|
||||
@@ -240,28 +291,28 @@ class Amp(_JsonThing):
|
||||
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:
|
||||
msg = f'missing preamp/booster variety input for amplifier: {type_variety} in equipment config'
|
||||
raise EquipmentConfigError(msg)
|
||||
except KeyError as exc:
|
||||
raise EquipmentConfigError(f'missing preamp/booster variety input for amplifier: {type_variety}'
|
||||
+ ' in equipment config') from exc
|
||||
dual_stage_def = Model_dual_stage(preamp_variety, booster_variety)
|
||||
elif type_def == 'multi_band':
|
||||
amplifiers = kwargs['amplifiers']
|
||||
else:
|
||||
raise EquipmentConfigError(f'Edfa type_def {type_def} does not exist')
|
||||
|
||||
json_data = load_json(config)
|
||||
|
||||
return cls(**{**kwargs, **json_data,
|
||||
'nf_model': nf_def, 'dual_stage_model': dual_stage_def})
|
||||
# raise an error if config does not contain f_min, f_max
|
||||
if 'f_min' not in config or 'f_max' not in config:
|
||||
raise EquipmentConfigError(f'Config file {config_filename} does not contain f_min and f_max values.'
|
||||
+ ' Please correct file.')
|
||||
# use f_min, f_max from kwargs
|
||||
if 'f_min' in kwargs:
|
||||
config.pop('f_min', None)
|
||||
config.pop('f_max', None)
|
||||
return cls(**{**kwargs, **config,
|
||||
'nf_model': nf_def, 'dual_stage_model': dual_stage_def, 'multi_band': amplifiers})
|
||||
|
||||
|
||||
def _automatic_spacing(baud_rate):
|
||||
"""return the min possible channel spacing for a given baud rate"""
|
||||
# TODO : this should parametrized in a cfg file
|
||||
# list of possible tuples [(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)
|
||||
|
||||
|
||||
def _spectrum_from_json(json_data):
|
||||
def _spectrum_from_json(json_data: dict):
|
||||
"""JSON_data is a list of spectrum partitions each with
|
||||
{f_min, f_max, baud_rate, roll_off, delta_pdb, slot_width, tx_osnr, label}
|
||||
Creates the per freq Carrier's dict.
|
||||
@@ -303,17 +354,13 @@ def _spectrum_from_json(json_data):
|
||||
previous_part_max_freq = 0.0
|
||||
for index, part in enumerate(json_data):
|
||||
# default delta_pdb is 0 dB
|
||||
if 'delta_pdb' not in part:
|
||||
part['delta_pdb'] = 0
|
||||
part.setdefault('delta_pdb', 0)
|
||||
# add a label to the partition for the printings
|
||||
if 'label' not in part:
|
||||
part['label'] = f'{index}-{part["baud_rate"] * 1e-9 :.2f}G'
|
||||
part.setdefault('label', f'{index}-{part["baud_rate"] * 1e-9:.2f}G')
|
||||
# default tx_osnr is set to 40 dB
|
||||
if 'tx_osnr' not in part:
|
||||
part['tx_osnr'] = 40
|
||||
part.setdefault('tx_osnr', 40)
|
||||
# default tx_power_dbm is set to 0 dBn
|
||||
if 'tx_power_dbm' not in part:
|
||||
part['tx_power_dbm'] = 0
|
||||
part.setdefault('tx_power_dbm', 0)
|
||||
# starting freq is exactly f_min to be consistent with utils.automatic_nch
|
||||
# first partition min occupation is f_min - slot_width / 2 (central_frequency is f_min)
|
||||
# supposes that carriers are centered on frequency
|
||||
@@ -321,12 +368,13 @@ def _spectrum_from_json(json_data):
|
||||
# check that previous part last channel does not overlap on next part first channel
|
||||
# max center of the part should be below part['f_max'] and aligned on the slot_width
|
||||
msg = 'Not a valid initial spectrum definition:\nprevious spectrum last carrier max occupation ' +\
|
||||
f'{previous_part_max_freq * 1e-12 :.5f}GHz ' +\
|
||||
f'{previous_part_max_freq * 1e-12:.5f}GHz ' +\
|
||||
'overlaps on next spectrum first carrier occupation ' +\
|
||||
f'{(part["f_min"] - part["slot_width"] / 2) * 1e-12 :.5f}GHz'
|
||||
f'{(part["f_min"] - part["slot_width"] / 2) * 1e-12:.5f}GHz'
|
||||
raise ValueError(msg)
|
||||
|
||||
max_range = ((part['f_max'] - part['f_min']) // part['slot_width'] + 1) * part['slot_width']
|
||||
previous_part_max_freq = None
|
||||
for current_freq in arange(part['f_min'],
|
||||
part['f_min'] + max_range,
|
||||
part['slot_width']):
|
||||
@@ -338,17 +386,86 @@ def _spectrum_from_json(json_data):
|
||||
return spectrum
|
||||
|
||||
|
||||
def load_equipment(filename):
|
||||
json_data = load_json(filename)
|
||||
return _equipment_from_json(json_data, filename)
|
||||
def merge_equipment(equipment: Dict, extra_equipments: Dict[str, Dict], extra_configs: Dict[str, Dict]):
|
||||
"""Merge additional equipment libraries into the base equipment dictionary.
|
||||
Typical case is the use of third party transceivers which are not part of a the supplier library.
|
||||
|
||||
raise warnings if the same reference is used on two different libraries
|
||||
"""
|
||||
for filename, json_data in extra_equipments.items():
|
||||
extra_eqpt = _equipment_from_json(json_data, extra_configs)
|
||||
# populate with default eqpt to streamline loading
|
||||
for eqpt_type, extra_items in extra_eqpt.items():
|
||||
for type_variety, item in extra_items.items():
|
||||
if type_variety not in equipment[eqpt_type]:
|
||||
equipment[eqpt_type][type_variety] = item
|
||||
else:
|
||||
msg = f'\n\tEquipment file {filename}: duplicate equipment entry found: {eqpt_type}-{type_variety}\n'
|
||||
_logger.warning(msg)
|
||||
|
||||
|
||||
def load_initial_spectrum(filename):
|
||||
json_data = load_json(filename)
|
||||
def load_equipments_and_configs(equipment_filename: Path,
|
||||
extra_equipment_filenames: List[Path],
|
||||
extra_config_filenames: List[Path]) -> Dict:
|
||||
"""Loads equipment configurations and merge with additional equipment and configuration files.
|
||||
|
||||
:param equipment_filename: The path to the primary equipment configuration file.
|
||||
:type equipment_filename: Path
|
||||
:param extra_equipment_filenames: A list of paths to additional equipment configuration files to merge.
|
||||
:type extra_equipment_filenames: List[Path]
|
||||
:param extra_config_filenames: A list of paths to additional configuration files to include.
|
||||
:type extra_config_filenames: List[Path]
|
||||
:return: A dictionary containing the loaded equipment configurations.
|
||||
:rtype: Dict
|
||||
|
||||
Notes:
|
||||
If no equipment filename is provided, a default equipment configuration will be used.
|
||||
Additional configurations from `extra_config_filenames` will override the default configurations.
|
||||
If `extra_equipment_filenames` are provided, their contents will be merged into the loaded equipment.
|
||||
"""
|
||||
extra_configs = DEFAULT_EXTRA_CONFIG
|
||||
if not equipment_filename:
|
||||
equipment_filename = DEFAULT_EQPT_CONFIG
|
||||
if extra_config_filenames:
|
||||
# All files must have different filenames (as filename is used as the key in the library)
|
||||
filename_list = [f.name for f in extra_config_filenames]
|
||||
if len(set(filename_list)) != len(extra_config_filenames):
|
||||
msg = f'Identical filenames for extra-config {filename_list}'
|
||||
_logger.error(msg)
|
||||
raise ConfigurationError(msg)
|
||||
extra_configs = {f.name: load_json(f) for f in extra_config_filenames}
|
||||
for k, v in DEFAULT_EXTRA_CONFIG.items():
|
||||
extra_configs[k] = v
|
||||
equipment = load_equipment(equipment_filename, extra_configs)
|
||||
if extra_equipment_filenames:
|
||||
# use the string representation of the path to support identical filenames but placed in different folders.
|
||||
extra_equipments = {f.as_posix(): load_json(f) for f in extra_equipment_filenames}
|
||||
merge_equipment(equipment, extra_equipments, extra_configs)
|
||||
return equipment
|
||||
|
||||
|
||||
def load_equipment(filename: Path, extra_configs: Dict[str, Dict] = DEFAULT_EXTRA_CONFIG) -> Dict:
|
||||
"""Load equipment, returns equipment dict
|
||||
"""
|
||||
json_data = load_gnpy_json(filename)
|
||||
return _equipment_from_json(json_data, extra_configs)
|
||||
|
||||
|
||||
def load_initial_spectrum(filename: Path) -> dict:
|
||||
"""Load spectrum to propagate, returns spectrum dict
|
||||
"""
|
||||
json_data = load_gnpy_json(filename)
|
||||
return _spectrum_from_json(json_data['spectrum'])
|
||||
|
||||
|
||||
def _update_dual_stage(equipment):
|
||||
def _update_dual_stage(equipment: dict):
|
||||
"""Update attributes of all dual stage amps with the preamp and booster attributes
|
||||
(defined in the equipment dictionary)
|
||||
|
||||
Returns the updated equiment dictionary
|
||||
"""
|
||||
if 'Edfa' not in equipment:
|
||||
return
|
||||
edfa_dict = equipment['Edfa']
|
||||
for edfa in edfa_dict.values():
|
||||
if edfa.type_def == 'dual_stage':
|
||||
@@ -367,8 +484,35 @@ def _update_dual_stage(equipment):
|
||||
return equipment
|
||||
|
||||
|
||||
def _roadm_restrictions_sanity_check(equipment):
|
||||
def _update_band(equipment: dict):
|
||||
"""Creates a list of bands for this amplifier, and remove other parameters which are not applicable
|
||||
"""
|
||||
if 'Edfa' not in equipment:
|
||||
return
|
||||
amp_dict = equipment['Edfa']
|
||||
for amplifier in amp_dict.values():
|
||||
if amplifier.type_def != 'multi_band':
|
||||
amplifier.bands = [{'f_min': amplifier.f_min,
|
||||
'f_max': amplifier.f_max}]
|
||||
# updates band parameter
|
||||
else:
|
||||
_bands = [{'f_min': amp_dict[a].f_min,
|
||||
'f_max': amp_dict[a].f_max} for a in amp_dict[amplifier.type_variety].multi_band]
|
||||
# remove duplicates
|
||||
amplifier.bands = []
|
||||
for b in _bands:
|
||||
if b not in amplifier.bands:
|
||||
amplifier.bands.append(b)
|
||||
# remove non applicable parameters
|
||||
for key in ['f_min', 'f_max', 'gain_flatmax', 'gain_min', 'p_max', 'nf_model', 'dual_stage_model',
|
||||
'nf_fit_coeff', 'nf_ripple', 'dgt', 'gain_ripple']:
|
||||
delattr(amplifier, key)
|
||||
|
||||
|
||||
def _roadm_restrictions_sanity_check(equipment: dict):
|
||||
"""verifies that booster and preamp restrictions specified in roadm equipment are listed in the edfa."""
|
||||
if 'Roadm' not in equipment:
|
||||
return equipment
|
||||
for roadm_type, roadm_eqpt in equipment['Roadm'].items():
|
||||
restrictions = roadm_eqpt.restrictions['booster_variety_list'] + \
|
||||
roadm_eqpt.restrictions['preamp_variety_list']
|
||||
@@ -378,7 +522,7 @@ def _roadm_restrictions_sanity_check(equipment):
|
||||
+ 'defined EDFA name')
|
||||
|
||||
|
||||
def _check_fiber_vs_raman_fiber(equipment):
|
||||
def _check_fiber_vs_raman_fiber(equipment: dict):
|
||||
"""Ensure that Fiber and RamanFiber with the same name define common properties equally"""
|
||||
if 'RamanFiber' not in equipment:
|
||||
return
|
||||
@@ -393,7 +537,20 @@ def _check_fiber_vs_raman_fiber(equipment):
|
||||
f'disagrees for "{attr}": {a} != {b}')
|
||||
|
||||
|
||||
def _equipment_from_json(json_data, filename):
|
||||
def _si_sanity_check(equipment):
|
||||
"""Check that 'default' key correctly exists in SI list. (There must be at list one element and it must be default)
|
||||
If not create one entry in the list with this key.
|
||||
"""
|
||||
if 'SI' not in equipment:
|
||||
return
|
||||
possible_SI = list(equipment['SI'].keys())
|
||||
if 'default' not in possible_SI:
|
||||
# Use "default" key in the equipment, using the first listed keys
|
||||
equipment['SI']['default'] = equipment['SI'][possible_SI[0]]
|
||||
del equipment['SI'][possible_SI[0]]
|
||||
|
||||
|
||||
def _equipment_from_json(json_data: dict, extra_configs: Dict[str, Dict]) -> Dict:
|
||||
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
||||
edfa type type_variety, fiber type_variety
|
||||
from the eqpt_config.json (filename parameter)
|
||||
@@ -408,7 +565,7 @@ def _equipment_from_json(json_data, filename):
|
||||
for entry in entries:
|
||||
subkey = entry.get('type_variety', 'default')
|
||||
if key == 'Edfa':
|
||||
equipment[key][subkey] = Amp.from_json(filename, **entry)
|
||||
equipment[key][subkey] = Amp.from_json(extra_configs, **entry)
|
||||
elif key == 'Fiber':
|
||||
equipment[key][subkey] = Fiber(**entry)
|
||||
elif key == 'Span':
|
||||
@@ -427,16 +584,23 @@ def _equipment_from_json(json_data, filename):
|
||||
else:
|
||||
raise EquipmentConfigError(f'Unrecognized network element type "{key}"')
|
||||
_check_fiber_vs_raman_fiber(equipment)
|
||||
equipment = _update_dual_stage(equipment)
|
||||
_update_dual_stage(equipment)
|
||||
_update_band(equipment)
|
||||
_roadm_restrictions_sanity_check(equipment)
|
||||
_si_sanity_check(equipment)
|
||||
return equipment
|
||||
|
||||
|
||||
def load_network(filename, equipment):
|
||||
def load_network(filename: Path, equipment: dict) -> DiGraph:
|
||||
"""load network json or excel
|
||||
|
||||
:param filename: input file to read from
|
||||
:param equipment: equipment library
|
||||
"""
|
||||
if filename.suffix.lower() in ('.xls', '.xlsx'):
|
||||
json_data = xls_to_json_data(filename)
|
||||
elif filename.suffix.lower() == '.json':
|
||||
json_data = load_json(filename)
|
||||
json_data = load_gnpy_json(filename)
|
||||
else:
|
||||
raise ValueError(f'unsupported topology filename extension {filename.suffix.lower()}')
|
||||
return network_from_json(json_data, equipment)
|
||||
@@ -456,28 +620,80 @@ def _cls_for(equipment_type):
|
||||
return elements.Edfa
|
||||
if equipment_type == 'Fused':
|
||||
return elements.Fused
|
||||
elif equipment_type == 'Roadm':
|
||||
if equipment_type == 'Roadm':
|
||||
return elements.Roadm
|
||||
elif equipment_type == 'Transceiver':
|
||||
if equipment_type == 'Transceiver':
|
||||
return elements.Transceiver
|
||||
elif equipment_type == 'Fiber':
|
||||
if equipment_type == 'Fiber':
|
||||
return elements.Fiber
|
||||
elif equipment_type == 'RamanFiber':
|
||||
if equipment_type == 'RamanFiber':
|
||||
return elements.RamanFiber
|
||||
else:
|
||||
raise ConfigurationError(f'Unknown network equipment "{equipment_type}"')
|
||||
if equipment_type == 'Multiband_amplifier':
|
||||
return elements.Multiband_amplifier
|
||||
raise ConfigurationError(f'Unknown network equipment "{equipment_type}"')
|
||||
|
||||
|
||||
def network_from_json(json_data, equipment):
|
||||
def network_from_json(json_data: dict, equipment: dict) -> DiGraph:
|
||||
"""create digraph based on json input dict and using equipment library to fill in the gaps
|
||||
"""
|
||||
# NOTE|dutc: we could use the following, but it would tie our data format
|
||||
# too closely to the graph library
|
||||
# from networkx import node_link_graph
|
||||
g = DiGraph()
|
||||
g.graph['network_name'] = json_data.get('network_name', None)
|
||||
for el_config in json_data['elements']:
|
||||
typ = el_config.pop('type')
|
||||
variety = el_config.pop('type_variety', 'default')
|
||||
cls = _cls_for(typ)
|
||||
if typ == 'Fused':
|
||||
if typ == 'Transceiver':
|
||||
temp = el_config.setdefault('params', {})
|
||||
if typ == 'Multiband_amplifier':
|
||||
if variety in ['default', '']:
|
||||
extra_params = None
|
||||
temp = el_config.setdefault('params', {})
|
||||
temp = merge_amplifier_restrictions(temp, deepcopy(MultiBandParams.default_values))
|
||||
el_config['params'] = temp
|
||||
else:
|
||||
extra_params = equipment['Edfa'][variety]
|
||||
temp = el_config.setdefault('params', {})
|
||||
# use config params preferably to library params, only use library params to fill in
|
||||
# the missing attribute
|
||||
temp = merge_amplifier_restrictions(temp, deepcopy(extra_params.__dict__))
|
||||
el_config['params'] = temp
|
||||
el_config['type_variety'] = variety
|
||||
# if config does not contain any amp list create one
|
||||
amps = el_config.setdefault('amplifiers', [])
|
||||
for amp in amps:
|
||||
amp_variety = amp['type_variety'] # juste pour essayer
|
||||
amp_extra_params = equipment['Edfa'][amp_variety]
|
||||
temp = amp.setdefault('params', {})
|
||||
temp = merge_amplifier_restrictions(temp, amp_extra_params.__dict__)
|
||||
amp['params'] = temp
|
||||
amp['type_variety'] = amp_variety
|
||||
# check type_variety consistant with amps type_variety
|
||||
if amps:
|
||||
try:
|
||||
multiband_type_variety = find_type_variety([a['type_variety'] for a in amps], equipment)
|
||||
except ConfigurationError as e:
|
||||
msg = f'Node {el_config["uid"]}: {e}'
|
||||
raise ConfigurationError(msg)
|
||||
if variety is not None and variety not in multiband_type_variety:
|
||||
raise ConfigurationError(f'In node {el_config["uid"]}: multiband amplifier type_variety is not '
|
||||
+ 'consistent with its amps type varieties.')
|
||||
if not amps and extra_params is not None:
|
||||
# the amp config does not contain the amplifiers operational settings, but has a type_variety
|
||||
# defined so that it is possible to create the template of amps for design for each band. This
|
||||
# defines the default design bands.
|
||||
# This lopp populates each amp with default values, for each band
|
||||
for band in extra_params.bands:
|
||||
params = {k: v for k, v in Amp.default_values.items()}
|
||||
# update frequencies with band values
|
||||
params['f_min'] = band['f_min']
|
||||
params['f_max'] = band['f_max']
|
||||
amps.append({'params': params})
|
||||
# without type_variety, it is not possible to set the amplifier dict at this point: need to wait
|
||||
# for design, and use user defined design-bands
|
||||
elif typ == 'Fused':
|
||||
# well, there's no variety for the 'Fused' node type
|
||||
pass
|
||||
elif variety in equipment[typ]:
|
||||
@@ -491,6 +707,9 @@ def network_from_json(json_data, equipment):
|
||||
if not extra_params:
|
||||
msg = f'ROADM {el_config["uid"]}: invalid equalization settings'
|
||||
raise ConfigurationError(msg)
|
||||
# use temp pmd_coef if it exists else use the default one from library and keep this knowledge in
|
||||
# pmd_coef_defined
|
||||
use_pmd_coef(temp, extra_params)
|
||||
temp = merge_amplifier_restrictions(temp, extra_params)
|
||||
el_config['params'] = temp
|
||||
el_config['type_variety'] = variety
|
||||
@@ -516,14 +735,16 @@ def network_from_json(json_data, equipment):
|
||||
else:
|
||||
edge_length = 0.01
|
||||
g.add_edge(nodes[from_node], nodes[to_node], weight=edge_length)
|
||||
except KeyError:
|
||||
except KeyError as exc:
|
||||
msg = f'can not find {from_node} or {to_node} defined in {cx}'
|
||||
raise NetworkTopologyError(msg)
|
||||
raise NetworkTopologyError(msg) from exc
|
||||
|
||||
return g
|
||||
|
||||
|
||||
def network_to_json(network):
|
||||
def network_to_json(network: DiGraph) -> dict:
|
||||
"""Export network graph as a json dict
|
||||
"""
|
||||
data = {
|
||||
'elements': [n.to_json for n in network]
|
||||
}
|
||||
@@ -534,56 +755,82 @@ def network_to_json(network):
|
||||
for next_n in network.successors(n) if next_n is not None]
|
||||
}
|
||||
data.update(connections)
|
||||
if network.graph['network_name']:
|
||||
data['network_name'] = network.graph['network_name']
|
||||
return data
|
||||
|
||||
|
||||
def load_json(filename):
|
||||
def load_json(filename: Path) -> dict:
|
||||
"""load json data
|
||||
|
||||
:param filename: Path to the file to convert
|
||||
:type filemname: Path
|
||||
:return: json data in a dictionnary
|
||||
:rtype: Dict
|
||||
"""
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
return data
|
||||
|
||||
|
||||
def save_json(obj, filename):
|
||||
def load_gnpy_json(filename: Path) -> dict:
|
||||
"""load json data. It supports both legacy ang yang formatted inputs based on yang models.
|
||||
|
||||
:param filename: Path to the file to convert
|
||||
:type filemname: Path
|
||||
:return: json data in a dictionnary
|
||||
:rtype: Dict
|
||||
"""
|
||||
return yang_to_legacy(load_json(filename))
|
||||
|
||||
|
||||
def save_json(obj: dict, filename: Path):
|
||||
"""Save in json format. Export yang formatted data (RFC7951)
|
||||
"""
|
||||
data = legacy_to_yang(obj)
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
json.dump(obj, f, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
def load_requests(filename, eqpt, bidir, network, network_filename):
|
||||
def load_requests(filename: Path, eqpt: dict, bidir: bool, network: DiGraph, network_filename: str) -> dict:
|
||||
"""loads the requests from a json or an excel file into a data string"""
|
||||
if filename.suffix.lower() in ('.xls', '.xlsx'):
|
||||
_logger.info('Automatically converting requests from XLS to JSON')
|
||||
try:
|
||||
return convert_service_sheet(filename, eqpt, network, network_filename=network_filename, bidir=bidir)
|
||||
except ServiceError as this_e:
|
||||
raise ServiceError(f'Service error: {this_e}')
|
||||
raise ServiceError(f'Service error: {this_e}') from this_e
|
||||
else:
|
||||
return load_json(filename)
|
||||
|
||||
|
||||
def requests_from_json(json_data, equipment):
|
||||
def requests_from_json(json_data: dict, equipment: dict) -> List[PathRequest]:
|
||||
"""Extract list of requests from data parsed from JSON"""
|
||||
requests_list = []
|
||||
|
||||
for req in json_data['path-request']:
|
||||
# init all params from request
|
||||
params = {}
|
||||
params['request_id'] = f'{req["request-id"]}'
|
||||
params['source'] = req['source']
|
||||
params['bidir'] = req['bidirectional']
|
||||
params['destination'] = req['destination']
|
||||
params['trx_type'] = req['path-constraints']['te-bandwidth']['trx_type']
|
||||
if params['trx_type'] is None:
|
||||
trx_type = req['path-constraints']['te-bandwidth']['trx_type']
|
||||
trx_mode = req['path-constraints']['te-bandwidth'].get('trx_mode', None)
|
||||
if trx_type is None:
|
||||
msg = f'Request {req["request-id"]} has no transceiver type defined.'
|
||||
raise ServiceError(msg)
|
||||
params['trx_mode'] = req['path-constraints']['te-bandwidth'].get('trx_mode', None)
|
||||
params['format'] = params['trx_mode']
|
||||
params['spacing'] = req['path-constraints']['te-bandwidth']['spacing']
|
||||
try:
|
||||
nd_list = sorted(req['explicit-route-objects']['route-object-include-exclude'], key=lambda x: x['index'])
|
||||
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]
|
||||
params = {
|
||||
'request_id': f'{req["request-id"]}',
|
||||
'source': req['source'],
|
||||
'destination': req['destination'],
|
||||
'bidir': req['bidirectional'],
|
||||
'trx_type': trx_type,
|
||||
'trx_mode': trx_mode,
|
||||
'format': trx_mode,
|
||||
'spacing': req['path-constraints']['te-bandwidth']['spacing'],
|
||||
'nodes_list': [n['num-unnum-hop']['node-id'] for n in nd_list],
|
||||
'loose_list': [n['num-unnum-hop']['hop-type'] for n in nd_list]
|
||||
}
|
||||
# recover trx physical param (baudrate, ...) from type and mode
|
||||
# nb_channel is computed based on min max frequency and spacing
|
||||
try:
|
||||
@@ -629,7 +876,7 @@ def requests_from_json(json_data, equipment):
|
||||
return requests_list
|
||||
|
||||
|
||||
def _check_one_request(params, f_max_from_si):
|
||||
def _check_one_request(params: dict, f_max_from_si: float):
|
||||
"""Checks that the requested parameters are consistant (spacing vs nb channel vs transponder mode...)"""
|
||||
f_min = params['f_min']
|
||||
f_max = params['f_max']
|
||||
@@ -639,19 +886,19 @@ def _check_one_request(params, f_max_from_si):
|
||||
if params['min_spacing'] > params['spacing']:
|
||||
msg = f'Request {params["request_id"]} has spacing below transponder ' +\
|
||||
f'{params["trx_type"]} {params["trx_mode"]} min spacing value ' +\
|
||||
f'{params["min_spacing"]*1e-9}GHz.\nComputation stopped'
|
||||
f'{params["min_spacing"] * 1e-9}GHz.\nComputation stopped'
|
||||
raise ServiceError(msg)
|
||||
if f_max > f_max_from_si:
|
||||
msg = f'Requested channel number {params["nb_channel"]}, baud rate {params["baud_rate"] * 1e-9} GHz' \
|
||||
+ f' and requested spacing {params["spacing"]*1e-9}GHz is not consistent with frequency range' \
|
||||
+ f' {f_min*1e-12} THz, {f_max_from_si*1e-12} THz.' \
|
||||
+ f' and requested spacing {params["spacing"] * 1e-9}GHz is not consistent with frequency range' \
|
||||
+ f' {f_min * 1e-12} THz, {f_max_from_si * 1e-12} THz.' \
|
||||
+ f' Max recommanded nb of channels is {max_recommanded_nb_channels}.'
|
||||
raise ServiceError(msg)
|
||||
# Transponder mode already selected; will it fit to the requested bandwidth?
|
||||
if params['trx_mode'] is not None and params['effective_freq_slot'] is not None:
|
||||
required_nb_of_channels, requested_m = compute_spectrum_slot_vs_bandwidth(params['path_bandwidth'],
|
||||
params['spacing'],
|
||||
params['bit_rate'])
|
||||
required_nb_of_channels, _ = compute_spectrum_slot_vs_bandwidth(params['path_bandwidth'],
|
||||
params['spacing'],
|
||||
params['bit_rate'])
|
||||
_, per_channel_m = compute_spectrum_slot_vs_bandwidth(params['bit_rate'],
|
||||
params['spacing'],
|
||||
params['bit_rate'])
|
||||
@@ -690,7 +937,7 @@ def _check_one_request(params, f_max_from_si):
|
||||
i += 1
|
||||
|
||||
|
||||
def disjunctions_from_json(json_data):
|
||||
def disjunctions_from_json(json_data: dict) -> List[Disjunction]:
|
||||
"""reads the disjunction requests from the json dict and create the list
|
||||
of requested disjunctions for this set of requests
|
||||
"""
|
||||
@@ -709,20 +956,30 @@ def disjunctions_from_json(json_data):
|
||||
|
||||
|
||||
def convert_service_sheet(
|
||||
input_filename,
|
||||
eqpt,
|
||||
network,
|
||||
network_filename=None,
|
||||
output_filename='',
|
||||
bidir=False):
|
||||
input_filename: Path,
|
||||
eqpt: dict,
|
||||
network: DiGraph,
|
||||
network_filename: Union[Path, None] = None,
|
||||
output_filename: str = '',
|
||||
bidir: bool = False):
|
||||
"""Converts xls into json format services
|
||||
|
||||
:param input_filename: xls(x) file containing the service sheet
|
||||
:param eqpt: equipment library
|
||||
:param network: network for which these services apply (required for xls inputs to correct names)
|
||||
:param network_filename: optional network file name that was used for network creation
|
||||
(required for xls inputs to correct names)
|
||||
:param output_filename: name of the file where converted data are savec
|
||||
:param bidir: set all services bidir attribute with this bool
|
||||
"""
|
||||
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'
|
||||
data = read_service_sheet(input_filename, eqpt, network, network_filename, bidir)
|
||||
save_json(data, output_filename)
|
||||
return data
|
||||
|
||||
|
||||
def find_equalisation(params, equalization_types):
|
||||
def find_equalisation(params: Dict, equalization_types: List[str]):
|
||||
"""Find the equalization(s) defined in params. params can be a dict or a Roadm object.
|
||||
|
||||
>>> roadm = {'add_drop_osnr': 100, 'pmd': 1, 'pdl': 0.5,
|
||||
@@ -739,7 +996,7 @@ def find_equalisation(params, equalization_types):
|
||||
return equalization
|
||||
|
||||
|
||||
def merge_equalization(params, extra_params):
|
||||
def merge_equalization(params: dict, extra_params: dict) -> Union[dict, None]:
|
||||
"""params contains ROADM element config and extra_params default values from equipment library.
|
||||
If equalization is not defined in ROADM element use the one defined in equipment library.
|
||||
Only one type of equalization must be defined: power (target_pch_out_db) or PSD (target_psd_out_mWperGHz)
|
||||
@@ -759,3 +1016,42 @@ def merge_equalization(params, extra_params):
|
||||
# If ROADM config doesn't contain any equalization type, keep the default one
|
||||
return extra_params
|
||||
return None
|
||||
|
||||
|
||||
def results_to_json(pathresults: List[ResultElement]):
|
||||
"""Converts a list of `ResultElement` objects into a JSON-compatible dictionary.
|
||||
|
||||
:param pathresults: List of `ResultElement` objects to be converted.
|
||||
:return: A dictionary with a single key `"response"`, containing a list of
|
||||
the `json` attributes of the provided `ResultElement` objects.
|
||||
"""
|
||||
return {'response': [n.json for n in pathresults]}
|
||||
|
||||
|
||||
def load_eqpt_topo_from_json(eqpt: dict, topology: dict, extra_equipments: Optional[Dict[str, Dict]] = None,
|
||||
extra_configs: Dict[str, Dict] = DEFAULT_EXTRA_CONFIG) -> Tuple[dict, DiGraph]:
|
||||
"""Loads equipment configuration and network topology from JSON data.
|
||||
|
||||
:param eqpt: Dictionary containing the equipment configuration in JSON format.
|
||||
It includes details about the devices to be processed and structured.
|
||||
:type eqpt: dict
|
||||
:param topology: Dictionary representing the network topology in JSON format,
|
||||
defining the structure of the network and its connections.
|
||||
:type topology: dict
|
||||
:param extra_equipments: dictionary containing additional libraries (eg for pluggables). Key can be
|
||||
the file Path or any other string.
|
||||
:type extra_equipments: Optional[Dict[str, Dict]]
|
||||
:param extra_configs: Additional configurations for amplifiers in the library
|
||||
:type extra_configs: Dict[str, Dict]
|
||||
|
||||
:return: A tuple containing:
|
||||
|
||||
- A dictionary with the processed equipment configuration.
|
||||
- A directed graph (DiGraph) representing the network topology, where nodes
|
||||
correspond to equipment and edges define their connections.
|
||||
"""
|
||||
equipment = _equipment_from_json(eqpt, extra_configs)
|
||||
if extra_equipments:
|
||||
merge_equipment(equipment, extra_equipments, extra_configs)
|
||||
network = network_from_json(topology, equipment)
|
||||
return equipment, network
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.tools.plots: Graphs and plots usable from a CLI application
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.tools.plots
|
||||
================
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.tools.service_sheet: XLS parser that can be called to create a JSON request file
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.tools.service_sheet
|
||||
========================
|
||||
@@ -11,105 +16,181 @@ Yang model for requesting path computation.
|
||||
See: draft-ietf-teas-yang-path-computation-01.txt
|
||||
"""
|
||||
|
||||
from xlrd import open_workbook, XL_CELL_EMPTY
|
||||
from collections import namedtuple
|
||||
from logging import getLogger
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Generator
|
||||
from networkx import DiGraph
|
||||
|
||||
from gnpy.core.utils import db2lin
|
||||
from gnpy.core.exceptions import ServiceError
|
||||
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fiber
|
||||
from gnpy.tools.convert import corresp_names, corresp_next_node
|
||||
from gnpy.tools.convert import corresp_names, corresp_next_node, all_rows, generic_open_workbook, get_sheet, \
|
||||
parse_row, parse_headers
|
||||
from gnpy.tools.xls_utils import correct_cell_int_to_str, get_sheet_name, is_type_cell_empty
|
||||
|
||||
|
||||
SERVICES_COLUMN = 12
|
||||
|
||||
|
||||
def all_rows(sheet, start=0):
|
||||
return (sheet.row(x) for x in range(start, sheet.nrows))
|
||||
SERVICE_LINE = 4
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class Request(namedtuple('Request', 'request_id source destination trx_type mode \
|
||||
spacing power nb_channel disjoint_from nodes_list is_loose path_bandwidth')):
|
||||
def __new__(cls, request_id, source, destination, trx_type, mode=None, spacing=None, power=None, nb_channel=None, disjoint_from='', nodes_list=None, is_loose='', path_bandwidth=None):
|
||||
return super().__new__(cls, request_id, source, destination, trx_type, mode, spacing, power, nb_channel, disjoint_from, nodes_list, is_loose, path_bandwidth)
|
||||
class Request:
|
||||
"""DATA class for a request.
|
||||
|
||||
:params request_id (int): The unique identifier for the request.
|
||||
:params source (str): The source node for the communication.
|
||||
:params destination (str): The destination node for the communication.
|
||||
:params trx_type (str): The type of transmission for the communication.
|
||||
:params mode (str, optional): The mode of transmission. Defaults to None.
|
||||
:params spacing (float, optional): The spacing between channels. Defaults to None.
|
||||
:params power (float, optional): The power level for the communication. Defaults to None.
|
||||
:params nb_channel (int, optional): The number of channels required for the communication. Defaults to None.
|
||||
:params disjoint_from (str, optional): The node to be disjoint from. Defaults to ''.
|
||||
:params nodes_list (list, optional): The list of nodes involved in the communication. Defaults to None.
|
||||
:params is_loose (str, optional): Indicates if the communication is loose. Defaults to ''.
|
||||
:params path_bandwidth (float, optional): The bandwidth required for the communication. Defaults to None.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
"""Constructor method
|
||||
"""
|
||||
super().__init__()
|
||||
self.update_attr(kwargs)
|
||||
|
||||
def update_attr(self, kwargs):
|
||||
"""Updates the attributes of the node based on provided keyword arguments.
|
||||
|
||||
:param kwargs: A dictionary of attributes to update.
|
||||
"""
|
||||
clean_kwargs = {k: v for k, v in kwargs.items() if v != '' and v is not None}
|
||||
for k, v in self.default_values.items():
|
||||
v = clean_kwargs.get(k, v)
|
||||
if k != 'is_loose':
|
||||
if k in ['request_id', 'trx_type', 'mode', 'disjoint_from']:
|
||||
v = correct_cell_int_to_str(v)
|
||||
setattr(self, k, v)
|
||||
else:
|
||||
self.is_loose = v in ['', None, 'yes', 'Yes', 'YES']
|
||||
|
||||
default_values = {
|
||||
'request_id': None,
|
||||
'source': None,
|
||||
'destination': None,
|
||||
'trx_type': None,
|
||||
'mode': None,
|
||||
'spacing': None,
|
||||
'power': None,
|
||||
'nb_channel': None,
|
||||
'disjoint_from': '',
|
||||
'nodes_list': '',
|
||||
'is_loose': None,
|
||||
'path_bandwidth': None
|
||||
}
|
||||
|
||||
|
||||
class Element:
|
||||
"""
|
||||
"""
|
||||
def __init__(self, uid):
|
||||
self.uid = uid
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.uid == other.uid
|
||||
return isinstance(other, type(self)) and self.uid == other.ui
|
||||
|
||||
def __hash__(self):
|
||||
return hash((type(self), self.uid))
|
||||
|
||||
|
||||
class Request_element(Element):
|
||||
def __init__(self, Request, equipment, bidir):
|
||||
"""Class that generate the request in the json format
|
||||
|
||||
:params request_param (Request): The request object containing the information for the element.
|
||||
:params equipment (dict): The equipment configuration for the communication.
|
||||
:params bidir (bool): Indicates if the communication is bidirectional.
|
||||
|
||||
Attributes:
|
||||
request_id (str): The unique identifier for the request.
|
||||
source (str): The source node for the communication.
|
||||
destination (str): The destination node for the communication.
|
||||
srctpid (str): The source TP ID for the communication.
|
||||
dsttpid (str): The destination TP ID for the communication.
|
||||
bidir (bool): Indicates if the communication is bidirectional.
|
||||
trx_type (str): The type of transmission for the communication.
|
||||
mode (str): The mode of transmission for the communication.
|
||||
spacing (float): The spacing between channels for the communication.
|
||||
power (float): The power level for the communication.
|
||||
nb_channel (int): The number of channels required for the communication.
|
||||
disjoint_from (list): The list of nodes to be disjoint from.
|
||||
nodes_list (list): The list of nodes involved in the communication.
|
||||
loose (str): Indicates if the communication is loose or strict.
|
||||
path_bandwidth (float): The bandwidth required for the communication.
|
||||
"""
|
||||
def __init__(self, request_param: Request, equipment: Dict, bidir: bool):
|
||||
"""
|
||||
"""
|
||||
super().__init__(uid=request_param.request_id)
|
||||
# request_id is str
|
||||
# excel has automatic number formatting that adds .0 on integer values
|
||||
# the next lines recover the pure int value, assuming this .0 is unwanted
|
||||
self.request_id = correct_xlrd_int_to_str_reading(Request.request_id)
|
||||
self.source = f'trx {Request.source}'
|
||||
self.destination = f'trx {Request.destination}'
|
||||
# TODO: the automatic naming generated by excel parser requires that source and dest name
|
||||
self.request_id = request_param.request_id
|
||||
self.source = f'trx {request_param.source}'
|
||||
self.destination = f'trx {request_param.destination}'
|
||||
# The automatic naming generated by excel parser requires that source and dest name
|
||||
# be a string starting with 'trx' : this is manually added here.
|
||||
self.srctpid = f'trx {Request.source}'
|
||||
self.dsttpid = f'trx {Request.destination}'
|
||||
self.srctpid = f'trx {request_param.source}'
|
||||
self.dsttpid = f'trx {request_param.destination}'
|
||||
self.bidir = bidir
|
||||
# test that trx_type belongs to eqpt_config.json
|
||||
# if not replace it with a default
|
||||
self.mode = None
|
||||
try:
|
||||
if equipment['Transceiver'][Request.trx_type]:
|
||||
self.trx_type = correct_xlrd_int_to_str_reading(Request.trx_type)
|
||||
if Request.mode is not None:
|
||||
Requestmode = correct_xlrd_int_to_str_reading(Request.mode)
|
||||
if [mode for mode in equipment['Transceiver'][Request.trx_type].mode if mode['format'] == Requestmode]:
|
||||
self.mode = Requestmode
|
||||
available_modes = [mode['format'] for mode in equipment['Transceiver'][request_param.trx_type].mode]
|
||||
self.trx_type = request_param.trx_type
|
||||
if request_param.mode not in [None, '']:
|
||||
if request_param.mode in available_modes:
|
||||
self.mode = request_param.mode
|
||||
else:
|
||||
msg = f'Request Id: {self.request_id} - could not find tsp : \'{Request.trx_type}\' ' \
|
||||
+ f'with mode: \'{Requestmode}\' in eqpt library \nComputation stopped.'
|
||||
msg = f'Request Id: {self.request_id} - could not find tsp : \'{request_param.trx_type}\' ' \
|
||||
+ f'with mode: \'{request_param.mode}\' in eqpt library \nComputation stopped.'
|
||||
raise ServiceError(msg)
|
||||
else:
|
||||
Requestmode = None
|
||||
self.mode = Request.mode
|
||||
except KeyError:
|
||||
msg = f'Request Id: {self.request_id} - could not find tsp : \'{Request.trx_type}\' ' \
|
||||
+ f'with mode: \'{Request.mode}\' in eqpt library \nComputation stopped.'
|
||||
raise ServiceError(msg)
|
||||
except KeyError as e:
|
||||
msg = f'Request Id: {self.request_id} - could not find tsp : \'{request_param.trx_type}\' with mode: ' \
|
||||
+ f'\'{request_param.mode}\' in eqpt library \nComputation stopped.'
|
||||
raise ServiceError(msg) from e
|
||||
# excel input are in GHz and dBm
|
||||
if Request.spacing is not None:
|
||||
self.spacing = Request.spacing * 1e9
|
||||
if request_param.spacing:
|
||||
self.spacing = request_param.spacing * 1e9
|
||||
else:
|
||||
msg = f'Request {self.request_id} missing spacing: spacing is mandatory.\ncomputation stopped'
|
||||
raise ServiceError(msg)
|
||||
if Request.power is not None:
|
||||
self.power = db2lin(Request.power) * 1e-3
|
||||
else:
|
||||
self.power = None
|
||||
if Request.nb_channel is not None:
|
||||
self.nb_channel = int(Request.nb_channel)
|
||||
else:
|
||||
self.nb_channel = None
|
||||
|
||||
value = correct_xlrd_int_to_str_reading(Request.disjoint_from)
|
||||
self.disjoint_from = [n for n in value.split(' | ') if value]
|
||||
self.power = None
|
||||
if request_param.power is not None:
|
||||
self.power = db2lin(request_param.power) * 1e-3
|
||||
|
||||
self.nb_channel = None
|
||||
if request_param.nb_channel is not None:
|
||||
self.nb_channel = int(request_param.nb_channel)
|
||||
|
||||
self.disjoint_from = [n for n in request_param.disjoint_from.split(' | ') if request_param.disjoint_from]
|
||||
self.nodes_list = []
|
||||
if Request.nodes_list:
|
||||
self.nodes_list = Request.nodes_list.split(' | ')
|
||||
self.loose = 'LOOSE'
|
||||
if Request.is_loose.lower() == 'no':
|
||||
self.loose = 'STRICT'
|
||||
self.path_bandwidth = None
|
||||
if Request.path_bandwidth is not None:
|
||||
self.path_bandwidth = Request.path_bandwidth * 1e9
|
||||
else:
|
||||
self.path_bandwidth = 0
|
||||
if request_param.nodes_list:
|
||||
self.nodes_list = request_param.nodes_list.split(' | ')
|
||||
|
||||
uid = property(lambda self: repr(self))
|
||||
self.loose = 'LOOSE'
|
||||
if not request_param.is_loose:
|
||||
self.loose = 'STRICT'
|
||||
|
||||
self.path_bandwidth = 0
|
||||
if request_param.path_bandwidth is not None:
|
||||
self.path_bandwidth = request_param.path_bandwidth * 1e9
|
||||
|
||||
@property
|
||||
def pathrequest(self):
|
||||
"""Creates json dictionnary for the request
|
||||
"""
|
||||
# Default assumption for bidir is False
|
||||
req_dictionnary = {
|
||||
'request-id': self.request_id,
|
||||
@@ -134,14 +215,15 @@ class Request_element(Element):
|
||||
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),
|
||||
'num-unnum-hop': {
|
||||
'node-id': f'{node}',
|
||||
'link-tp-id': 'link-tp-id is not used',
|
||||
'hop-type': f'{self.loose}',
|
||||
}
|
||||
}
|
||||
{
|
||||
'index': self.nodes_list.index(node),
|
||||
'explicit-route-usage': 'route-include-ero',
|
||||
'num-unnum-hop': {
|
||||
'node-id': f'{node}',
|
||||
'link-tp-id': 'link-tp-id is not used',
|
||||
'hop-type': f'{self.loose}',
|
||||
}
|
||||
}
|
||||
for node in self.nodes_list]
|
||||
}
|
||||
req_dictionnary['explicit-route-objects'] = temp
|
||||
@@ -152,29 +234,32 @@ class Request_element(Element):
|
||||
|
||||
@property
|
||||
def pathsync(self):
|
||||
"""Creates json dictionnary for disjunction list (synchronization vector)
|
||||
"""
|
||||
if self.disjoint_from:
|
||||
return {'synchronization-id': self.request_id,
|
||||
'svec': {
|
||||
'relaxable': 'false',
|
||||
'disjointness': 'node link',
|
||||
'request-id-number': [self.request_id] + [n for n in self.disjoint_from]
|
||||
'request-id-number': [self.request_id] + list(self.disjoint_from)
|
||||
}
|
||||
}
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
# TO-DO: avoid multiple entries with same synchronisation vectors
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
"""Returns the json dictionnary for requests and for synchronisation vector
|
||||
"""
|
||||
return self.pathrequest, self.pathsync
|
||||
|
||||
|
||||
def read_service_sheet(
|
||||
input_filename,
|
||||
eqpt,
|
||||
network,
|
||||
network_filename=None,
|
||||
bidir=False):
|
||||
input_filename: Path,
|
||||
eqpt: Dict,
|
||||
network: DiGraph,
|
||||
network_filename: Path = None,
|
||||
bidir: bool = False) -> Dict:
|
||||
""" converts a service sheet into a json structure
|
||||
"""
|
||||
if network_filename is None:
|
||||
@@ -184,69 +269,86 @@ def read_service_sheet(
|
||||
req = correct_xls_route_list(network_filename, network, req)
|
||||
# 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]
|
||||
data = {'path-request': [n.json[0] for n in req]}
|
||||
if synchro:
|
||||
data = {
|
||||
'path-request': [n.json[0] for n in req],
|
||||
'synchronization': synchro
|
||||
}
|
||||
else:
|
||||
data = {
|
||||
'path-request': [n.json[0] for n in req]
|
||||
}
|
||||
data['synchronization'] = synchro
|
||||
return data
|
||||
|
||||
|
||||
def correct_xlrd_int_to_str_reading(v):
|
||||
if not isinstance(v, str):
|
||||
value = str(int(v))
|
||||
if value.endswith('.0'):
|
||||
value = value[:-2]
|
||||
else:
|
||||
value = v
|
||||
return value
|
||||
|
||||
|
||||
def parse_row(row, fieldnames):
|
||||
return {f: r.value for f, r in zip(fieldnames, row[0:SERVICES_COLUMN])
|
||||
if r.ctype != XL_CELL_EMPTY}
|
||||
|
||||
|
||||
def parse_excel(input_filename):
|
||||
with open_workbook(input_filename) as wb:
|
||||
service_sheet = wb.sheet_by_name('Service')
|
||||
services = list(parse_service_sheet(service_sheet))
|
||||
def parse_excel(input_filename: Path) -> List[Request]:
|
||||
"""Open xls_file and reads 'Service' sheet
|
||||
Returns the list of services data in Request class
|
||||
"""
|
||||
wb, is_xlsx = generic_open_workbook(input_filename)
|
||||
service_sheet = get_sheet(wb, 'Service', is_xlsx)
|
||||
services = list(parse_service_sheet(service_sheet, is_xlsx))
|
||||
return services
|
||||
|
||||
|
||||
def parse_service_sheet(service_sheet):
|
||||
def parse_service_sheet(service_sheet, is_xlsx) -> Generator[Request, None, None]:
|
||||
""" reads each column according to authorized fieldnames. order is not important.
|
||||
"""
|
||||
logger.debug(f'Validating headers on {service_sheet.name!r}')
|
||||
logger.debug('Validating headers on %r', get_sheet_name(service_sheet, is_xlsx))
|
||||
# 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
|
||||
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
|
||||
# to be compatible with any version of the sheet
|
||||
# the following dictionnary records the excel field names and the corresponding parameter's name
|
||||
|
||||
authorized_fieldnames = {
|
||||
'route id': 'request_id', 'Source': 'source', 'Destination': 'destination',
|
||||
'TRX type': 'trx_type', 'Mode': 'mode', 'System: spacing': 'spacing',
|
||||
'System: input power (dBm)': 'power', 'System: nb of channels': 'nb_channel',
|
||||
'routing: disjoint from': 'disjoint_from', 'routing: path': 'nodes_list',
|
||||
'routing: is loose?': 'is_loose', 'path bandwidth': 'path_bandwidth'}
|
||||
try:
|
||||
service_fieldnames = [authorized_fieldnames[e] for e in header]
|
||||
except KeyError:
|
||||
msg = f'Malformed header on Service sheet: {header} field not in {authorized_fieldnames}'
|
||||
raise ValueError(msg)
|
||||
for row in all_rows(service_sheet, start=5):
|
||||
yield Request(**parse_row(row[0:SERVICES_COLUMN], service_fieldnames))
|
||||
header = parse_headers(service_sheet, is_xlsx, authorized_fieldnames, {}, SERVICE_LINE, (0, SERVICES_COLUMN))
|
||||
|
||||
# create a service_fieldname independant from the excel column order
|
||||
# to be compatible with any version of the sheet
|
||||
# the following dictionnary records the excel field names and the corresponding parameter's name
|
||||
|
||||
for row in all_rows(service_sheet, is_xlsx, start=5):
|
||||
if not is_type_cell_empty(row[0], is_xlsx):
|
||||
# Check required because openpyxl in read_only mode can return "ghost" rows at the end of the document
|
||||
# (ReadOnlyCell cells with no actual value but formatting information even for empty rows).
|
||||
yield Request(**parse_row(row[0:SERVICES_COLUMN], header))
|
||||
|
||||
|
||||
def correct_xls_route_list(network_filename, network, pathreqlist):
|
||||
def check_end_points(pathreq: Request_element, network: DiGraph):
|
||||
"""Raise error if end point is not correct
|
||||
"""
|
||||
transponders = [n.uid for n in network.nodes() if isinstance(n, Transceiver)]
|
||||
if pathreq.source not in transponders:
|
||||
msg = f'Request: {pathreq.request_id}: could not find' +\
|
||||
f' transponder source : {pathreq.source}.'
|
||||
logger.critical(msg)
|
||||
raise ServiceError(msg)
|
||||
if pathreq.destination not in transponders:
|
||||
msg = f'Request: {pathreq.request_id}: could not find' +\
|
||||
f' transponder destination: {pathreq.destination}.'
|
||||
logger.critical(msg)
|
||||
raise ServiceError(msg)
|
||||
|
||||
|
||||
def find_node_sugestion(n_id, corresp_roadm, corresp_fused, corresp_ila, network):
|
||||
"""
|
||||
"""
|
||||
roadmtype = [n.uid for n in network.nodes() if isinstance(n, Roadm)]
|
||||
edfatype = [n.uid for n in network.nodes() if isinstance(n, Edfa)]
|
||||
# check that n_id is in the node list, if not find a correspondance name
|
||||
if n_id in roadmtype + edfatype:
|
||||
return [n_id]
|
||||
# checks first roadm, fused, and ila in this order, because ila automatic name
|
||||
# contains roadm names. If it is a fused node, next ila names might be correct
|
||||
# suggestions, especially if following fibers were splitted and ila names
|
||||
# created with the name of the fused node
|
||||
if n_id in corresp_roadm.keys():
|
||||
return corresp_roadm[n_id]
|
||||
if n_id in corresp_fused.keys():
|
||||
return corresp_fused[n_id] + corresp_ila[n_id]
|
||||
if n_id in corresp_ila.keys():
|
||||
return corresp_ila[n_id]
|
||||
return []
|
||||
|
||||
|
||||
def correct_xls_route_list(network_filename: Path, network: DiGraph,
|
||||
pathreqlist: List[Request_element]) -> List[Request_element]:
|
||||
""" prepares the format of route list of nodes to be consistant with nodes names:
|
||||
remove wrong names, find correct names for ila, roadm and fused if the entry was
|
||||
xls.
|
||||
@@ -260,30 +362,17 @@ def correct_xls_route_list(network_filename, network, pathreqlist):
|
||||
corresp_ila, next_node = corresp_next_node(network, corresp_ila, corresp_roadm)
|
||||
# finally correct constraints based on these dict
|
||||
trxfibertype = [n.uid for n in network.nodes() if isinstance(n, (Transceiver, Fiber))]
|
||||
roadmtype = [n.uid for n in network.nodes() if isinstance(n, Roadm)]
|
||||
edfatype = [n.uid for n in network.nodes() if isinstance(n, Edfa)]
|
||||
# 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)]
|
||||
for pathreq in pathreqlist:
|
||||
# first check that source and dest are transceivers
|
||||
if pathreq.source not in transponders:
|
||||
msg = f'Request: {pathreq.request_id}: could not find' +\
|
||||
f' transponder source : {pathreq.source}.'
|
||||
raise ServiceError(msg)
|
||||
|
||||
if pathreq.destination not in transponders:
|
||||
msg = f'Request: {pathreq.request_id}: could not find' +\
|
||||
f' transponder destination: {pathreq.destination}.'
|
||||
raise ServiceError(msg)
|
||||
check_end_points(pathreq, network)
|
||||
# silently pop source and dest nodes from the list if they were added by the user as first
|
||||
# and last elem in the constraints respectively. Other positions must lead to an error
|
||||
# caught later on
|
||||
if pathreq.nodes_list and pathreq.source == pathreq.nodes_list[0]:
|
||||
pathreq.loose_list.pop(0)
|
||||
pathreq.nodes_list.pop(0)
|
||||
if pathreq.nodes_list and pathreq.destination == pathreq.nodes_list[-1]:
|
||||
pathreq.loose_list.pop(-1)
|
||||
pathreq.nodes_list.pop(-1)
|
||||
# Then process user defined constraints with respect to automatic namings
|
||||
temp = deepcopy(pathreq)
|
||||
@@ -293,73 +382,56 @@ def correct_xls_route_list(network_filename, network, pathreqlist):
|
||||
# n_id must not be a transceiver and must not be a fiber (non supported, user
|
||||
# can not enter fiber names in excel)
|
||||
if n_id not in trxfibertype:
|
||||
# check that n_id is in the node list, if not find a correspondance name
|
||||
if n_id in roadmtype + edfatype:
|
||||
nodes_suggestion = [n_id]
|
||||
else:
|
||||
# checks first roadm, fused, and ila in this order, because ila automatic name
|
||||
# contain roadm names. If it is a fused node, next ila names might be correct
|
||||
# suggestions, especially if following fibers were splitted and ila names
|
||||
# created with the name of the fused node
|
||||
if n_id in corresp_roadm.keys():
|
||||
nodes_suggestion = corresp_roadm[n_id]
|
||||
elif n_id in corresp_fused.keys():
|
||||
nodes_suggestion = corresp_fused[n_id] + corresp_ila[n_id]
|
||||
elif n_id in corresp_ila.keys():
|
||||
nodes_suggestion = corresp_ila[n_id]
|
||||
nodes_suggestion = find_node_sugestion(n_id, corresp_roadm, corresp_fused, corresp_ila, network)
|
||||
try:
|
||||
if len(nodes_suggestion) > 1:
|
||||
# if there is more than one suggestion, we need to choose the direction
|
||||
# we rely on the next node provided by the user for this purpose
|
||||
new_n = next(n for n in nodes_suggestion
|
||||
if n in next_node
|
||||
and next_node[n] in temp.nodes_list[i:] + [pathreq.destination]
|
||||
and next_node[n] not in temp.nodes_list[:i])
|
||||
elif len(nodes_suggestion) == 1:
|
||||
new_n = nodes_suggestion[0]
|
||||
else:
|
||||
nodes_suggestion = []
|
||||
if nodes_suggestion:
|
||||
try:
|
||||
if len(nodes_suggestion) > 1:
|
||||
# if there is more than one suggestion, we need to choose the direction
|
||||
# we rely on the next node provided by the user for this purpose
|
||||
new_n = next(n for n in nodes_suggestion
|
||||
if n in next_node.keys() and next_node[n]
|
||||
in temp.nodes_list[i:] + [pathreq.destination] and
|
||||
next_node[n] not in temp.nodes_list[:i])
|
||||
else:
|
||||
new_n = nodes_suggestion[0]
|
||||
if new_n != n_id:
|
||||
# warns the user when the correct name is used only in verbose mode,
|
||||
# eg 'a' is a roadm and correct name is 'roadm a' or when there was
|
||||
# too much ambiguity, 'b' is an ila, its name can be:
|
||||
# Edfa0_fiber (a → b)-xx if next node is c or
|
||||
# Edfa0_fiber (c → b)-xx if next node is a
|
||||
msg = f'Request {pathreq.request_id}: Invalid route node specified:' \
|
||||
+ f'\n\t\'{n_id}\', replaced with \'{new_n}\''
|
||||
logger.warning(msg)
|
||||
pathreq.nodes_list[pathreq.nodes_list.index(n_id)] = new_n
|
||||
except StopIteration:
|
||||
# shall not come in this case, unless requested direction does not exist
|
||||
msg = f'Request {pathreq.request_id}: Invalid route specified {n_id}: could' \
|
||||
+ ' not decide on direction, skipped!.\nPlease add a valid' \
|
||||
+ ' direction in constraints (next neighbour node)'
|
||||
logger.warning(msg)
|
||||
pathreq.loose_list.pop(pathreq.nodes_list.index(n_id))
|
||||
pathreq.nodes_list.remove(n_id)
|
||||
else:
|
||||
if temp.loose_list[i] == 'LOOSE':
|
||||
# if no matching can be found in the network just ignore this constraint
|
||||
# if it is a loose constraint
|
||||
# warns the user that this node is not part of the topology
|
||||
msg = f'Request {pathreq.request_id}: Invalid node specified:\n\t\'{n_id}\'' \
|
||||
+ ', could not use it as constraint, skipped!'
|
||||
logger.warning(msg)
|
||||
pathreq.loose_list.pop(pathreq.nodes_list.index(n_id))
|
||||
pathreq.nodes_list.remove(n_id)
|
||||
else:
|
||||
msg = f'Request {pathreq.request_id}: Could not find node:\n\t\'{n_id}\' in network' \
|
||||
if temp.loose == 'LOOSE':
|
||||
# if no matching can be found in the network just ignore this constraint
|
||||
# if it is a loose constraint
|
||||
# warns the user that this node is not part of the topology
|
||||
msg = f'{pathreq.request_id}: Invalid node specified:\n\t\'{n_id}\'' \
|
||||
+ ', could not use it as constraint, skipped!'
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
pathreq.nodes_list.remove(n_id)
|
||||
continue
|
||||
msg = f'{pathreq.request_id}: Could not find node:\n\t\'{n_id}\' in network' \
|
||||
+ ' topology. Strict constraint can not be applied.'
|
||||
raise ServiceError(msg)
|
||||
if new_n != n_id:
|
||||
# warns the user when the correct name is used only in verbose mode,
|
||||
# eg 'a' is a roadm and correct name is 'roadm a' or when there was
|
||||
# too much ambiguity, 'b' is an ila, its name can be:
|
||||
# "east edfa in b to c", or "west edfa in b to a" if next node is c or
|
||||
# "west edfa in b to c", or "east edfa in b to a" if next node is a
|
||||
msg = f'{pathreq.request_id}: Invalid route node specified:' \
|
||||
+ f'\n\t\'{n_id}\', replaced with \'{new_n}\''
|
||||
logger.info(msg)
|
||||
pathreq.nodes_list[pathreq.nodes_list.index(n_id)] = new_n
|
||||
except StopIteration:
|
||||
# shall not come in this case, unless requested direction does not exist
|
||||
msg = f'{pathreq.request_id}: Invalid route specified {n_id}: could' \
|
||||
+ ' not decide on direction, skipped!.\nPlease add a valid' \
|
||||
+ ' direction in constraints (next neighbour node)'
|
||||
logger.info(msg)
|
||||
pathreq.nodes_list.remove(n_id)
|
||||
else:
|
||||
if temp.loose_list[i] == 'LOOSE':
|
||||
logger.warning(f'Request {pathreq.request_id}: Invalid route node specified:\n\t\'{n_id}\''
|
||||
+ ' type is not supported as constraint with xls network input, skipped!')
|
||||
pathreq.loose_list.pop(pathreq.nodes_list.index(n_id))
|
||||
if temp.loose == 'LOOSE':
|
||||
msg = f'{pathreq.request_id}: Invalid route node specified:\n\t\'{n_id}\'' \
|
||||
+ ' type is not supported as constraint with xls network input, skipped!'
|
||||
logger.warning(msg)
|
||||
pathreq.nodes_list.remove(n_id)
|
||||
else:
|
||||
msg = f'Invalid route node specified \n\t\'{n_id}\'' \
|
||||
msg = f'{pathreq.request_id}: Invalid route node specified \n\t\'{n_id}\'' \
|
||||
+ ' type is not supported as constraint with xls network input,' \
|
||||
+ ', Strict constraint can not be applied.'
|
||||
raise ServiceError(msg)
|
||||
|
||||
253
gnpy/tools/worker_utils.py
Normal file
253
gnpy/tools/worker_utils.py
Normal file
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.tools.worker_utils: Common code for CLI examples and API
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.tools.worker_utils
|
||||
=======================
|
||||
|
||||
Common code for CLI examples and API
|
||||
"""
|
||||
import logging
|
||||
from copy import deepcopy
|
||||
from typing import Union, List, Tuple
|
||||
from numpy import linspace
|
||||
from networkx import DiGraph
|
||||
|
||||
from gnpy.core.utils import automatic_nch, watt2dbm, dbm2watt, pretty_summary_print, per_label_average
|
||||
from gnpy.core.equipment import trx_mode_params
|
||||
from gnpy.core.network import add_missing_elements_in_network, design_network
|
||||
from gnpy.core import exceptions
|
||||
from gnpy.core.info import SpectralInformation
|
||||
from gnpy.topology.spectrum_assignment import build_oms_list, pth_assign_spectrum, OMS
|
||||
from gnpy.topology.request import correct_json_route_list, deduplicate_disjunctions, requests_aggregation, \
|
||||
compute_path_dsjctn, compute_path_with_disjunction, ResultElement, PathRequest, Disjunction, \
|
||||
compute_constrained_path, propagate
|
||||
from gnpy.tools.json_io import requests_from_json, disjunctions_from_json
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def designed_network(equipment: dict, network: DiGraph, source: str = None, destination: str = None,
|
||||
nodes_list: List[str] = None, loose_list: List[str] = None,
|
||||
initial_spectrum: dict = None, no_insert_edfas: bool = False,
|
||||
args_power: Union[str, float, int] = None,
|
||||
service_req: PathRequest = None) -> Tuple[DiGraph, PathRequest, PathRequest]:
|
||||
"""Build the reference channels based on inputs and design the network for this reference channel, and build the
|
||||
channel to be propagated for the single transmission script.
|
||||
|
||||
Reference channel (target input power in spans, nb of channels, transceiver output power) is built using
|
||||
equipment['SI'] information. If indicated, with target input power in spans is updated with args_power.
|
||||
Channel to be propagated is using the same channel reference, except if different settings are provided
|
||||
with service_req and initial_spectrum. The service to be propagated uses specified source, destination
|
||||
and list nodes_list of include nodes constraint except if the service_req is specified.
|
||||
|
||||
Args:
|
||||
- equipment: a dictionary containing equipment information.
|
||||
- network: a directed graph representing the initial network.
|
||||
- no_insert_edfas: a boolean indicating whether to insert EDFAs in the network.
|
||||
- args_power: the power to be used for the network design.
|
||||
- service_req: the service request the user wants to propagate.
|
||||
- source: the source node for the channel to be propagated if no service_req is specified.
|
||||
- destination: the destination node for the channel to be propagated if no service_req is specified.
|
||||
- nodes_list: a list of nodes to be included ifor the channel to be propagated if no service_req is specified.
|
||||
- loose_list: a list of loose nodes to be included in the network design.
|
||||
- initial_spectrum: a dictionary representing the initial spectrum to propagate.
|
||||
|
||||
Returns:
|
||||
- The designed network.
|
||||
- The channel to propagate.
|
||||
- The reference channel used for the design.
|
||||
"""
|
||||
if loose_list is None:
|
||||
loose_list = []
|
||||
if nodes_list is None:
|
||||
nodes_list = []
|
||||
if not no_insert_edfas:
|
||||
add_missing_elements_in_network(network, equipment)
|
||||
|
||||
if not nodes_list:
|
||||
if destination:
|
||||
nodes_list = [destination]
|
||||
loose_list = ['STRICT']
|
||||
else:
|
||||
nodes_list = []
|
||||
loose_list = []
|
||||
params = {
|
||||
'request_id': 'reference',
|
||||
'trx_type': '',
|
||||
'trx_mode': '',
|
||||
'source': source,
|
||||
'destination': destination,
|
||||
'bidir': False,
|
||||
'nodes_list': nodes_list,
|
||||
'loose_list': loose_list,
|
||||
'format': '',
|
||||
'path_bandwidth': 0,
|
||||
'effective_freq_slot': None,
|
||||
'nb_channel': None if equipment['SI']['default'].use_si_channel_count_for_design is False
|
||||
else automatic_nch(equipment['SI']['default'].f_min, equipment['SI']['default'].f_max,
|
||||
equipment['SI']['default'].spacing),
|
||||
'power': dbm2watt(equipment['SI']['default'].power_dbm),
|
||||
'tx_power': dbm2watt(equipment['SI']['default'].power_dbm)
|
||||
}
|
||||
if equipment['SI']['default'].tx_power_dbm is not None:
|
||||
# use SI tx_power if present
|
||||
params['tx_power'] = dbm2watt(equipment['SI']['default'].tx_power_dbm)
|
||||
trx_params = trx_mode_params(equipment)
|
||||
params.update(trx_params)
|
||||
|
||||
# use args_power instead of si
|
||||
if args_power:
|
||||
params['power'] = dbm2watt(float(args_power))
|
||||
if equipment['SI']['default'].tx_power_dbm is None:
|
||||
params['tx_power'] = params['power']
|
||||
|
||||
# use si as reference channel
|
||||
reference_channel = PathRequest(**params)
|
||||
|
||||
if service_req:
|
||||
# use service_req as reference channel with si tx_power if service_req tx_power is None
|
||||
if service_req.tx_power is None:
|
||||
service_req.tx_power = params['tx_power']
|
||||
reference_channel = deepcopy(service_req)
|
||||
if equipment['SI']['default'].use_si_channel_count_for_design is False:
|
||||
reference_channel.nb_channel = None
|
||||
|
||||
design_network(reference_channel, network, equipment, set_connector_losses=True, verbose=True)
|
||||
|
||||
if initial_spectrum:
|
||||
params['nb_channel'] = len(initial_spectrum)
|
||||
|
||||
req = PathRequest(**params)
|
||||
if service_req:
|
||||
req = service_req
|
||||
|
||||
req.initial_spectrum = initial_spectrum
|
||||
return network, req, reference_channel
|
||||
|
||||
|
||||
def check_request_path_ids(rqs: List[PathRequest]):
|
||||
"""check that request ids are unique. Non unique ids, may
|
||||
mess the computation: better to stop the computation
|
||||
"""
|
||||
all_ids = [r.request_id for r in rqs]
|
||||
if len(all_ids) != len(set(all_ids)):
|
||||
for item in list(set(all_ids)):
|
||||
all_ids.remove(item)
|
||||
msg = f'Requests id {all_ids} are not unique'
|
||||
logger.error(msg)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
def planning(network: DiGraph, equipment: dict, data: dict, redesign: bool = False) \
|
||||
-> Tuple[List[OMS], list, list, List[PathRequest], List[Disjunction], List[ResultElement]]:
|
||||
"""Run planning
|
||||
data contain the service dict from json
|
||||
redesign True means that network is redesign using each request as reference channel
|
||||
when False it means that the design is made once and successive propagation use the settings
|
||||
computed with this design.
|
||||
"""
|
||||
oms_list = build_oms_list(network, equipment)
|
||||
rqs = requests_from_json(data, equipment)
|
||||
# check that request ids are unique.
|
||||
check_request_path_ids(rqs)
|
||||
rqs = correct_json_route_list(network, rqs)
|
||||
dsjn = disjunctions_from_json(data)
|
||||
logger.info('List of disjunctions:\n%s', dsjn)
|
||||
# need to warn or correct in case of wrong disjunction form
|
||||
# disjunction must not be repeated with same or different ids
|
||||
dsjn = deduplicate_disjunctions(dsjn)
|
||||
logger.info('Aggregating similar requests')
|
||||
rqs, dsjn = requests_aggregation(rqs, dsjn)
|
||||
logger.info('The following services have been requested:\n%s', rqs)
|
||||
# logger.info('Computing all paths with constraints for request %s', optical_path_result_id)
|
||||
|
||||
pths = compute_path_dsjctn(network, equipment, rqs, dsjn)
|
||||
logger.info('Propagating on selected path')
|
||||
propagatedpths, reversed_pths, reversed_propagatedpths = \
|
||||
compute_path_with_disjunction(network, equipment, rqs, pths, redesign=redesign)
|
||||
# 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.
|
||||
|
||||
# Allowed user_policy are first_fit and 2partition
|
||||
pth_assign_spectrum(pths, rqs, oms_list, reversed_pths)
|
||||
for i, rq in enumerate(rqs):
|
||||
if hasattr(rq, 'OSNR') and rq.OSNR:
|
||||
rq.osnr_with_sys_margin = rq.OSNR + equipment["SI"]["default"].sys_margins
|
||||
|
||||
# assumes that list of rqs and list of propgatedpths have same order
|
||||
result = [ResultElement(rq, pth, rpth) for rq, pth, rpth in zip(rqs, propagatedpths, reversed_propagatedpths)]
|
||||
return oms_list, propagatedpths, reversed_propagatedpths, rqs, dsjn, result
|
||||
|
||||
|
||||
def transmission_simulation(equipment: dict, network: DiGraph, req: PathRequest, ref_req: PathRequest) \
|
||||
-> Tuple[list, List[list], List[Union[float, int]], SpectralInformation]:
|
||||
"""Run simulation and returms the propagation result for each power sweep iteration.
|
||||
Args:
|
||||
- equipment: a dictionary containing equipment information.
|
||||
- network: network after being designed using ref_req. Any missing information (amp gain or delta_p) must have
|
||||
been filled using ref_req as reference channel previuos to this function.
|
||||
- req: channel to be propagated.
|
||||
- ref_req: the reference channel used for filling missing information in the network.
|
||||
In case of power sweep, network is redesigned using ref_req whose target input power in span is
|
||||
updated with the power step.
|
||||
|
||||
Returns a tuple containing:
|
||||
- path: last propagated path. Power sweep is not possible with gain mode (as gain targets are used)
|
||||
- propagations: list of propagated path for each power iteration
|
||||
- powers_dbm: list of power used for the power sweep
|
||||
- infos: last propagated spectral information
|
||||
"""
|
||||
power_mode = equipment['Span']['default'].power_mode
|
||||
logger.info('Power mode is set to %s=> it can be modified in eqpt_config.json - Span', power_mode)
|
||||
# initial network is designed using ref_req. that is that any missing information (amp gain or delta_p) is filled
|
||||
# using this ref_req.power, previous to any sweep requested later on.
|
||||
|
||||
pref_ch_db = watt2dbm(ref_req.power)
|
||||
p_ch_db = watt2dbm(req.power)
|
||||
path = compute_constrained_path(network, req)
|
||||
power_range = [0]
|
||||
if power_mode:
|
||||
# power cannot be changed in gain mode
|
||||
try:
|
||||
p_start, p_stop, p_step = equipment['SI']['default'].power_range_db
|
||||
p_num = abs(int(round((p_stop - p_start) / p_step))) + 1 if p_step != 0 else 1
|
||||
power_range = list(linspace(p_start, p_stop, p_num))
|
||||
except TypeError as e:
|
||||
msg = 'invalid power range definition in eqpt_config, should be power_range_db: [lower, upper, step]'
|
||||
logger.error(msg)
|
||||
raise exceptions.EquipmentConfigError(msg) from e
|
||||
|
||||
logger.info('Now propagating between %s and %s', req.source, req.destination)
|
||||
|
||||
propagations = []
|
||||
powers_dbm = []
|
||||
for dp_db in power_range:
|
||||
ref_req.power = dbm2watt(pref_ch_db + dp_db)
|
||||
req.power = dbm2watt(p_ch_db + dp_db)
|
||||
|
||||
# Power sweep is made to evaluate different span input powers, so redesign is mandatory for each power,
|
||||
# but no need to redesign if there are no power sweep
|
||||
if len(power_range) > 1:
|
||||
design_network(ref_req, network.subgraph(path), equipment, set_connector_losses=False, verbose=False)
|
||||
|
||||
infos = propagate(path, req, equipment)
|
||||
propagations.append(deepcopy(path))
|
||||
powers_dbm.append(pref_ch_db + dp_db)
|
||||
logger.info('\nChannels propagating: (Input optical power deviation in span = '
|
||||
+ f'{pretty_summary_print(per_label_average(infos.delta_pdb_per_channel, infos.label))}dB,\n'
|
||||
+ ' spacing = '
|
||||
+ f'{pretty_summary_print(per_label_average(infos.slot_width * 1e-9, infos.label))}GHz,\n'
|
||||
+ ' transceiver output power = '
|
||||
+ f'{pretty_summary_print(per_label_average(watt2dbm(infos.tx_power), infos.label))}dBm,\n'
|
||||
+ f' nb_channels = {infos.number_of_channels})')
|
||||
if not power_mode:
|
||||
logger.info('\n\tPropagating using gain targets: Input optical power deviation in span ignored')
|
||||
return path, propagations, powers_dbm, infos
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Reads JSON path result file and writes results to a CSV file
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
write_path_jsontocsv.py
|
||||
========================
|
||||
324
gnpy/tools/xls_utils.py
Normal file
324
gnpy/tools/xls_utils.py
Normal file
@@ -0,0 +1,324 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.tools.worker_utils: Utilities for reading and writing XLS, XLSX
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.tools.xls_utils
|
||||
====================
|
||||
|
||||
This module contains utilities for reading and writing XLS, XLSX
|
||||
|
||||
"""
|
||||
from pathlib import Path
|
||||
from typing import Generator, Tuple, List, Union, Optional, Iterator, Callable
|
||||
from openpyxl import load_workbook, Workbook
|
||||
from openpyxl.worksheet.worksheet import Worksheet
|
||||
from openpyxl.cell.cell import Cell as OpenpyxlCell
|
||||
from openpyxl.cell.read_only import ReadOnlyCell as OpenpyxlReadOnlyCell
|
||||
from openpyxl.utils.exceptions import InvalidFileException
|
||||
from xlrd import Book, open_workbook, XL_CELL_EMPTY
|
||||
from xlrd.sheet import Sheet as XlrdSheet, Cell as XlrdCell
|
||||
from xlrd.biffh import XLRDError
|
||||
|
||||
SheetType = Union[Worksheet, XlrdSheet]
|
||||
WorkbookType = Union[Workbook, Book]
|
||||
CellType = Union[OpenpyxlCell, OpenpyxlReadOnlyCell, XlrdCell]
|
||||
XLS_EXCEPTIONS = (InvalidFileException, KeyError, XLRDError)
|
||||
|
||||
|
||||
def generic_open_workbook(file_path: Union[str, Path]) -> Tuple[WorkbookType, bool]:
|
||||
"""Open an Excel file supporting both XLS or XLSX.
|
||||
|
||||
:param file_path: Path of excel file
|
||||
:type file_path: Union[str, Path]
|
||||
:return: Tuple (workbook, is_xlsx) where is_xlsx inidcate if the file is XLSX or not
|
||||
:rtype: Tuple[WorkbookType, bool]
|
||||
"""
|
||||
file_path = Path(file_path) if isinstance(file_path, str) else file_path
|
||||
|
||||
if file_path.suffix.lower() in ['.xlsx', '.xlsm']:
|
||||
return load_workbook(file_path, read_only=True, data_only=True), True
|
||||
return open_workbook(file_path), False
|
||||
|
||||
|
||||
def get_sheet(workbook: WorkbookType,
|
||||
sheet_name: str,
|
||||
is_xlsx: bool) -> SheetType:
|
||||
"""Get the Excel Sheet by name
|
||||
|
||||
:param workbook: Opened Excel workbook
|
||||
:type workbook: WorkbookType
|
||||
:param sheet_name: Sheet name
|
||||
:type sheet_name: SheetType
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:return: Excel sheet
|
||||
:rtype: SheetType
|
||||
"""
|
||||
if is_xlsx:
|
||||
return workbook[sheet_name]
|
||||
return workbook.sheet_by_name(sheet_name)
|
||||
|
||||
|
||||
def get_cell_value(sheet: SheetType, row: int, col: int, is_xlsx: bool) -> Optional[Union[str, int, float]]:
|
||||
"""Get the cell value
|
||||
|
||||
:param sheet: Excel sheet
|
||||
:type sheet: SheetType
|
||||
:param row: Line index (0-based)
|
||||
:type row: int
|
||||
:param col: Column index (0-based)
|
||||
:type: int
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:return: cell value
|
||||
:rtype: Optional[Union[str, int, float]]
|
||||
"""
|
||||
if is_xlsx:
|
||||
# openpyxl uses a 1-based index
|
||||
cell = sheet.cell(row=row + 1, column=col + 1)
|
||||
return cell.value
|
||||
# xlrd uses a 0-base index
|
||||
return sheet.cell(row, col).value
|
||||
|
||||
|
||||
def get_row(sheet: SheetType, row_index: int, is_xlsx: bool, get_rows=None) -> List[CellType]:
|
||||
"""Get row in a workbook sheet.
|
||||
|
||||
:param sheet: Excel sheet
|
||||
:type sheet: SheetType
|
||||
:param row_index: Line index (0-based)
|
||||
:type row_index: int
|
||||
:param is_xlsx: True si c'est un fichier XLSX, False si XLS
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:param get_rows: Optional function that returns preloaded rows (from fast_get_sheet_rows)
|
||||
:type get_rows: Optional[Callable]
|
||||
:return: List row cells
|
||||
:rtype: List[CellType]
|
||||
"""
|
||||
if is_xlsx:
|
||||
if get_rows is not None:
|
||||
# use fast access with aclosure function
|
||||
rows = get_rows()
|
||||
else:
|
||||
rows = list(sheet.rows)
|
||||
return rows[row_index] if row_index < len(rows) else []
|
||||
return sheet.row(row_index)
|
||||
|
||||
|
||||
def fast_get_sheet_rows(sheet: Worksheet) -> Callable:
|
||||
"""Preloads all rows from an Excel sheet for fast access.
|
||||
|
||||
This function loads the sheet data only once and returns a function
|
||||
that provides access to this preloaded data without having to query
|
||||
the Excel sheet on each access, which significantly improves performance,
|
||||
particularly with openpyxl.
|
||||
|
||||
:param sheet: Excel worksheet (openpyxl.worksheet.worksheet.Worksheet object)
|
||||
:type sheet: Worksheet
|
||||
:return: Function that returns the preloaded rows
|
||||
:rtype: Callable[[], List[Tuple[Cell, ...]]]
|
||||
|
||||
Usage example:
|
||||
> get_rows = fast_get_sheet_rows(sheet)
|
||||
> rows = get_rows() # Access to preloaded data
|
||||
> first_row = rows[0] # First row
|
||||
"""
|
||||
# Load all sheet rows into memory only once
|
||||
# This operation can be expensive, but it's performed only once
|
||||
# load the rows only once.
|
||||
preloaded_data = list(sheet.rows)
|
||||
|
||||
def get_rows():
|
||||
"""Inner function (clodure function) that returns the preloaded data.
|
||||
|
||||
This function doesn't reload the data on each call,
|
||||
it simply returns the reference to the already loaded data.
|
||||
|
||||
:return: List of preloaded rows
|
||||
:rtype: List[Tuple[Cell, ...]]
|
||||
"""
|
||||
return preloaded_data
|
||||
return get_rows
|
||||
|
||||
|
||||
def get_row_slice(sheet: SheetType, row_index: int, start_col: int, end_col: int, is_xlsx: bool,
|
||||
get_rows: Callable = None) -> Union[Tuple[CellType], List[CellType]]:
|
||||
"""Get a row slice.
|
||||
|
||||
:param sheet: Excel sheet
|
||||
:type sheet: SheetType
|
||||
:param row_index: Line index (0-based)
|
||||
:type row_index: int
|
||||
:param start_col: Index of start column (0-based)
|
||||
:type start_col: int
|
||||
:param end_col: Index of end column (0-based)
|
||||
:type end_col: int
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:param get_rows: Optional function that returns preloaded rows (from fast_get_sheet_rows)
|
||||
:type get_rows: Optional[Callable]
|
||||
:return: List of cells in the selected slice
|
||||
:rtype: List[CellType]
|
||||
"""
|
||||
if is_xlsx:
|
||||
if get_rows is not None:
|
||||
rows = get_rows()
|
||||
else:
|
||||
rows = list(sheet.rows)
|
||||
return rows[row_index][start_col:end_col] if row_index < len(rows) else []
|
||||
return sheet.row_slice(row_index, start_col, end_col)
|
||||
|
||||
|
||||
def convert_empty(cell_value: Optional[Union[str, int, float]]) -> Optional[Union[str, int, float]]:
|
||||
"""Convert empty string into None
|
||||
|
||||
:param cell_value: Cell value
|
||||
:type cell_value: Optional[Union[str, int, float]]
|
||||
|
||||
>>> convert_empty('')
|
||||
|
||||
>>> convert_empty('data')
|
||||
'data'
|
||||
|
||||
>>> convert_empty(123)
|
||||
123
|
||||
"""
|
||||
if cell_value == '':
|
||||
return None
|
||||
return cell_value
|
||||
|
||||
|
||||
def get_num_rows(sheet: SheetType, is_xlsx: bool, get_rows: Callable = None) -> int:
|
||||
"""Get the number of lines of an Excel sheet. Note that openpyxl in read_only mode can return "ghost" rows
|
||||
at the end (ReadOnlyCell cells with no actual value but formatting information even for empty rows).
|
||||
|
||||
:param sheet: Excel sheet
|
||||
:type sheet: SheetType
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:param get_rows: Optional function that returns preloaded rows (from fast_get_sheet_rows)
|
||||
:type get_rows: Optional[Callable]
|
||||
:return: Number of lines
|
||||
:rtype: int
|
||||
"""
|
||||
if is_xlsx:
|
||||
if get_rows is not None:
|
||||
return len(list(get_rows()))
|
||||
else:
|
||||
return len(list(sheet.rows))
|
||||
return sheet.nrows
|
||||
|
||||
|
||||
def is_type_cell_empty(cell, is_xlsx: bool) -> bool:
|
||||
"""Check is a cell is empty.
|
||||
|
||||
:param sheet: Excel sheet
|
||||
:type sheet: SheetType
|
||||
:param row: Line index (0-based)
|
||||
:type row: int
|
||||
:param col: Column index (0-based)
|
||||
:type: int
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:return: True if cell is empty, else returns False
|
||||
:rtype: bool
|
||||
"""
|
||||
if is_xlsx:
|
||||
return cell.value in [None, '']
|
||||
return cell.ctype == XL_CELL_EMPTY
|
||||
|
||||
|
||||
def get_sheet_name(sheet: SheetType, is_xlsx: bool) -> str:
|
||||
"""Get the name of the current sheet
|
||||
|
||||
:param sheet: Excel sheet
|
||||
:type sheet: SheetType
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:return: Name of the sheet
|
||||
:rtype: str
|
||||
"""
|
||||
if is_xlsx:
|
||||
return sheet.title
|
||||
return sheet.name
|
||||
|
||||
|
||||
def all_rows(sh: Worksheet, is_xlsx: bool, start: int = 0, get_rows: Callable = None) -> Generator[list, None, None]:
|
||||
"""Returns all rows of the xls(x) sheet starting from start row.
|
||||
|
||||
:param sh: sheet: Excel sheet
|
||||
:type sheet: SheetType
|
||||
:param start: The starting row index (0-based).
|
||||
:type start: int
|
||||
:param get_rows: Optional function that returns preloaded rows (from fast_get_sheet_rows)
|
||||
:type get_rows: Optional[Callable]
|
||||
:return: A generator yielding all rows from the specified starting index.
|
||||
:rtype: Generator[list, None, None]
|
||||
"""
|
||||
return (get_row(sh, x, is_xlsx, get_rows) for x in range(start, get_num_rows(sh, is_xlsx, get_rows)))
|
||||
|
||||
|
||||
def correct_cell_int_to_str(v: Optional[Union[str, int, float]]) -> Optional[Union[str, int, float]]:
|
||||
"""Ensure that int values in "id" cells are read as strings containing the int and
|
||||
do not use the automatic float conversion from xlrd or openpyxl
|
||||
|
||||
:param v: cell value to convert
|
||||
:type v: Optional[Union[str, int, float]]
|
||||
:return: corrected cell value
|
||||
:rtype: Optional[Union[str, int, float]]
|
||||
|
||||
>>> correct_cell_int_to_str(123)
|
||||
'123'
|
||||
>>> correct_cell_int_to_str(123.0)
|
||||
'123'
|
||||
>>> correct_cell_int_to_str('abc')
|
||||
'abc'
|
||||
>>> correct_cell_int_to_str(None)
|
||||
|
||||
"""
|
||||
if not isinstance(v, str) and v is not None:
|
||||
value = str(int(v))
|
||||
if value.endswith('.0'):
|
||||
value = value[:-2]
|
||||
else:
|
||||
value = v
|
||||
return value
|
||||
|
||||
|
||||
def get_all_sheets(workbook: WorkbookType, is_xlsx: bool) -> Iterator[SheetType]:
|
||||
"""Get all sheets from an Excel workbook.
|
||||
|
||||
:param workbook: Opened Excel workbook
|
||||
:type workbook: WorkbookType
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:return: Iterator of all sheets in the workbook
|
||||
:rtype: Iterator[SheetType]
|
||||
"""
|
||||
if is_xlsx:
|
||||
for sheet in workbook.worksheets:
|
||||
yield sheet
|
||||
else:
|
||||
for i in range(workbook.nsheets):
|
||||
yield workbook.sheet_by_index(i)
|
||||
|
||||
|
||||
def get_sheet_names(workbook: WorkbookType, is_xlsx: bool) -> List[str]:
|
||||
"""Get all sheet names from an Excel workbook.
|
||||
|
||||
:param workbook: Opened Excel workbook
|
||||
:type workbook: WorkbookType
|
||||
:param is_xlsx: True if this is an XLSX workbook, False if XLS
|
||||
:type is_xlsx: bool
|
||||
:return: List of sheet names
|
||||
:rtype: List[str]
|
||||
"""
|
||||
if is_xlsx:
|
||||
return workbook.sheetnames
|
||||
return workbook.sheet_names()
|
||||
960
gnpy/tools/yang_convert_utils.py
Normal file
960
gnpy/tools/yang_convert_utils.py
Normal file
@@ -0,0 +1,960 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Utils for yang <-> legacy format conversion
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
Utils for yang <-> legacy format conversion
|
||||
===========================================
|
||||
|
||||
Format conversion utils.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from copy import deepcopy
|
||||
from typing import Dict, Union, List, Any, NamedTuple
|
||||
import json
|
||||
import os
|
||||
|
||||
import oopt_gnpy_libyang as ly
|
||||
|
||||
from gnpy.yang.precision_dict import PRECISION_DICT
|
||||
|
||||
ELEMENTS_KEY = 'elements'
|
||||
ROADM_KEY = 'Roadm'
|
||||
PARAMS_KEY = 'params'
|
||||
METADATA_KEY = 'metadata'
|
||||
LOCATION_KEY = 'location'
|
||||
DEGREE_KEY = 'degree_uid'
|
||||
PATH_REQUEST_KEY = 'path-request'
|
||||
RESPONSE_KEY = 'response'
|
||||
SPECTRUM_KEY = 'spectrum'
|
||||
LOSS_COEF_KEY = 'loss_coef'
|
||||
LOSS_COEF_KEY_PER_FREQ = 'loss_coef_per_frequency'
|
||||
RAMAN_COEF_KEY = 'raman_coefficient'
|
||||
RAMAN_EFFICIENCY_KEY = 'raman_efficiency'
|
||||
EQPT_TYPES = ['Edfa', 'Transceiver', 'Fiber', 'Roadm']
|
||||
EDFA_CONFIG_KEYS = ['nf_fit_coeff', 'nf_ripple', 'gain_ripple', 'dgt']
|
||||
SIM_PARAMS_KEYS = ['raman_params', 'nli_params']
|
||||
TOPO_NMSP = 'gnpy-network-topology:topology'
|
||||
EQPT_NMSP = 'gnpy-eqpt-config:equipment'
|
||||
SERV_NMSP = 'gnpy-path-computation:services'
|
||||
RESP_NMSP = 'gnpy-path-computation:responses'
|
||||
EDFA_CONFIG_NMSP = 'gnpy-edfa-config:edfa-config'
|
||||
SIM_PARAMS_NMSP = 'gnpy-sim-params:sim-params'
|
||||
SPECTRUM_NMSP = 'gnpy-spectrum:spectrum'
|
||||
|
||||
|
||||
class PrettyFloat(float):
|
||||
""""A float subclass for formatting according to specific fraction digit requirements.
|
||||
|
||||
>>> PrettyFloat(3.1245)
|
||||
3.12
|
||||
>>> PrettyFloat(100.65, 5)
|
||||
100.65
|
||||
>>> PrettyFloat(2.1e-5, 8)
|
||||
0.000021
|
||||
>>> PrettyFloat(10, 3)
|
||||
10.0
|
||||
>>> PrettyFloat(-0.3110761646066259, 18)
|
||||
-0.3110761646066259
|
||||
"""
|
||||
def __new__(cls, value: float, fraction_digit: int = 2):
|
||||
"""Create a new instance of PrettyFloat"""
|
||||
instance = super().__new__(cls, value)
|
||||
instance.fraction_digit = fraction_digit
|
||||
instance.value = value
|
||||
return instance
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return the string representation of the float formatted to the specified fraction digits. It removes
|
||||
scientific notation ("e-x").
|
||||
"""
|
||||
# When fraction digit is over 16, the usual formatting does not works properly because of floating point issues.
|
||||
# For example -0.3110761646066259 is represented as "-0.311076164606625905". The following function makes
|
||||
# sure that the unwanted floating point issue does not change the value. Maximum fraction digit in YANG is 18.
|
||||
if self.fraction_digit in range(0, 19):
|
||||
temp = str(self.value)
|
||||
if 'e' in temp or '.' not in temp or self.fraction_digit < 17:
|
||||
formatted_value = f'{self:.{self.fraction_digit}f}' # noqa E231
|
||||
if '.' in formatted_value:
|
||||
formatted_value = formatted_value.rstrip('0')
|
||||
if formatted_value.endswith('.'):
|
||||
formatted_value += '0'
|
||||
return formatted_value
|
||||
if '.' in temp:
|
||||
parts = temp.split('.')
|
||||
formatted_value = parts[0] + '.' + parts[1][0:min(self.fraction_digit, len(parts[1]))]
|
||||
formatted_value = formatted_value.rstrip('0')
|
||||
if formatted_value.endswith('.'):
|
||||
formatted_value += '0'
|
||||
return formatted_value
|
||||
return temp
|
||||
raise ValueError(f'Fraction digit {self.fraction_digit} not handled')
|
||||
|
||||
|
||||
def gnpy_precision_dict() -> Dict[str, int]:
|
||||
"""Return a dictionary of fraction-digit definitions for GNPy.
|
||||
Precision correspond to fraction digit number if it is a decimal64 yang type, or 0 if it is an
|
||||
(u)int < 64 or -1 if it is a string or an (u)int64 type.
|
||||
|
||||
:return: Dictionnary mapping key names with digit numbers for values.
|
||||
:rtype: Dict[str, int]
|
||||
"""
|
||||
return PRECISION_DICT
|
||||
|
||||
|
||||
def convert_dict(data: Dict, fraction_digit: int = 2, precision: Union[Dict[str, int], None] = None) \
|
||||
-> Union[Dict, List, float, int, str, None]:
|
||||
"""Recursive conversion from float to str, conformed to RFC7951
|
||||
does not work for int64 (will not returm str as stated in standard)
|
||||
If nothing is stated precision is using gnpy_precision_dict.
|
||||
|
||||
:param data: the input dictionary to convert.
|
||||
:type data: data: Dict
|
||||
:param fraction_digit: the number of decimal places to format.
|
||||
:type fraction_digit: int
|
||||
:param precision: A dictionary defining precision for specific keys.
|
||||
:type precision: Union[Dict[str, int], None]
|
||||
:return: A new dictionary with converted values.
|
||||
:rtype: Dict
|
||||
|
||||
>>> convert_dict({"y": "amp", "t": "vn", "g": 25, "gamma": 0.0016, "p": 21.5, "o": True, \
|
||||
"output-power": 14.12457896})
|
||||
{'y': 'amp', 't': 'vn', 'g': '25.0', 'gamma': '0.0016', 'p': '21.5', 'o': True, 'output-power': '14.12457896'}
|
||||
"""
|
||||
if not precision:
|
||||
precision = gnpy_precision_dict()
|
||||
if isinstance(data, dict):
|
||||
for k, v in data.items():
|
||||
fraction_digit = precision.get(k, 2)
|
||||
data[k] = convert_dict(v, fraction_digit, precision=precision)
|
||||
elif isinstance(data, list):
|
||||
temp = deepcopy(data)
|
||||
for i, el in enumerate(temp):
|
||||
if isinstance(el, float):
|
||||
data[i] = PrettyFloat(el, fraction_digit)
|
||||
data[i] = str(data[i])
|
||||
else:
|
||||
data[i] = convert_dict(el, fraction_digit=fraction_digit, precision=precision)
|
||||
elif isinstance(data, bool):
|
||||
return data
|
||||
elif isinstance(data, int):
|
||||
data = PrettyFloat(data)
|
||||
data.fraction_digit = fraction_digit
|
||||
if fraction_digit > 0:
|
||||
return str(data)
|
||||
if fraction_digit < 0:
|
||||
return data
|
||||
return int(data)
|
||||
elif isinstance(data, float):
|
||||
data = PrettyFloat(data)
|
||||
data.fraction_digit = fraction_digit
|
||||
return str(data)
|
||||
return data
|
||||
|
||||
|
||||
def convert_back(data: Dict, fraction_digit: Union[int, None] = None, precision: Union[Dict[str, int], None] = None) \
|
||||
-> Union[Dict, List, float, int, str, None]:
|
||||
"""Recursively convert strings back to their original types int, float according to RFC7951.
|
||||
|
||||
:param data: the input dictionary to convert.
|
||||
:type data: Dict
|
||||
:param fraction_digit: the number of decimal places to format.
|
||||
:type fraction_digit: Union[int, None]
|
||||
:param precision: A dictionary defining precision for specific keys.
|
||||
:type precision: Union[Dict[str, int], None]
|
||||
:return: A new dictionary with converted values.
|
||||
:rtype: Dict
|
||||
|
||||
>>> a = {'y': 'amp', 't': 'vn', 'N': '25', 'gamma': '0.0000000000000016', 'p': '21.50', 'o': True, \
|
||||
'output-power': '14.12458'}
|
||||
>>> convert_back({'a': a, 'delta_power_range_db': ['12.3', '10.6', True]})
|
||||
{'a': {'y': 'amp', 't': 'vn', 'N': 25, 'gamma': 1.6e-15, 'p': '21.50', 'o': True, 'output-power': 14.12458}, \
|
||||
'delta_power_range_db': ['12.3', '10.6', True]}
|
||||
"""
|
||||
if not precision:
|
||||
precision = gnpy_precision_dict()
|
||||
if isinstance(data, dict):
|
||||
for k, v in data.items():
|
||||
fraction_digit = None
|
||||
if k in precision:
|
||||
fraction_digit = precision[k]
|
||||
data[k] = convert_back(v, fraction_digit, precision=precision)
|
||||
elif isinstance(data, list):
|
||||
for i, el in enumerate(data):
|
||||
if isinstance(el, str) and fraction_digit not in [None, -1]:
|
||||
data[i] = float(data[i])
|
||||
else:
|
||||
data[i] = convert_back(el, fraction_digit=fraction_digit, precision=precision)
|
||||
elif isinstance(data, (bool, int, float)):
|
||||
return data
|
||||
elif isinstance(data, str) and fraction_digit is not None:
|
||||
if fraction_digit > 0:
|
||||
return float(data)
|
||||
if fraction_digit < 0:
|
||||
return data
|
||||
return int(data)
|
||||
return data
|
||||
|
||||
|
||||
def model_path() -> Path:
|
||||
"""Filesystem path to YANG models.
|
||||
|
||||
return: path to the GNPy YANG modules.
|
||||
rtype: Path
|
||||
"""
|
||||
return Path(__file__).parent.parent / 'yang'
|
||||
|
||||
|
||||
def external_yang() -> Path:
|
||||
"""Filesystem to the IETF external yang modules.
|
||||
|
||||
return: path to the IETF modules.
|
||||
rtype: Path
|
||||
"""
|
||||
return Path(__file__).parent.parent / 'yang' / 'ext'
|
||||
|
||||
|
||||
def yang_lib() -> Path:
|
||||
"""Path to the json library of needed yang modules.
|
||||
|
||||
return: path to the library describing all modules and revisions for this gnpy release.
|
||||
rtype: Path
|
||||
"""
|
||||
return Path(__file__).parent.parent / 'yang' / 'yang-library-gnpy.json'
|
||||
|
||||
|
||||
def _create_context(yang_library) -> ly.Context:
|
||||
"""Prepare a libyang context for validating data against GNPy YANG models.
|
||||
|
||||
:param yang_library: path to the library describing all modules and revisions to be considered for the formatted
|
||||
string generation.
|
||||
:type yang_library: Path
|
||||
:return: Context used to hold all information about schemas.
|
||||
:rtype: ly.Context
|
||||
"""
|
||||
ly.set_log_options(ly.LogOptions.Log | ly.LogOptions.Store)
|
||||
ctx = ly.Context(str(model_path()) + os.pathsep + str(external_yang()),
|
||||
ly.ContextOptions.AllImplemented | ly.ContextOptions.DisableSearchCwd)
|
||||
with open(yang_library, 'r', encoding='utf-8') as file:
|
||||
data = json.load(file)
|
||||
yang_modules = [{'name': e['name'], 'revision': e['revision']}
|
||||
for e in data['ietf-yang-library:modules-state']['module']]
|
||||
for module in yang_modules:
|
||||
ctx.load_module(module['name'], revision=module['revision'])
|
||||
return ctx
|
||||
|
||||
|
||||
class ErrorMessage(NamedTuple):
|
||||
# pylint: disable=C0115
|
||||
what: str
|
||||
where: str
|
||||
|
||||
|
||||
def load_data(s: str, yang_library: Path = yang_lib()) -> ly.DataNode:
|
||||
"""Load data from YANG-based JSON input and validate them.
|
||||
|
||||
:param data: a string contating the json data to be loaded.
|
||||
:type data: str
|
||||
:param yang_library: path to the library describing all modules and revisions to be considered for the formatted
|
||||
string generation.
|
||||
:type yang_library: Path
|
||||
:return: DataNode containing the loaded data
|
||||
:rtype: ly.DataNode
|
||||
"""
|
||||
ctx = _create_context(yang_library)
|
||||
try:
|
||||
data = ctx.parse_data(s, ly.DataFormat.JSON,
|
||||
ly.ParseOptions.Strict | ly.ParseOptions.Ordered,
|
||||
ly.ValidationOptions.Present
|
||||
| ly.ValidationOptions.MultiError)
|
||||
except ly.Error as exc:
|
||||
raise ly.Error(exc, [ErrorMessage(err.message, err.path) for err in ctx.errors()]) from None
|
||||
return data
|
||||
|
||||
|
||||
def dump_data(data: Dict, yang_library: Path = yang_lib()) -> str:
|
||||
"""Creates a formatted string using oopt-gnpy-libyang.
|
||||
|
||||
:param data: a json dict with data already formatted
|
||||
:type data: Dict
|
||||
:param yang_library: path to the library describing all modules and revisions to be considered for the formatted
|
||||
string generation.
|
||||
:type yang_library: Path
|
||||
:return: formatted string data
|
||||
:rtype: str
|
||||
"""
|
||||
return load_data(json.dumps(data), yang_library).print(ly.DataFormat.JSON, ly.PrintFlags.WithSiblings)
|
||||
|
||||
|
||||
def convert_degree(json_data: Dict) -> Dict:
|
||||
"""Convert legacy json topology format to gnpy yang format revision 2025-01-20:
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: Dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if elem['type'] == ROADM_KEY and PARAMS_KEY in elem:
|
||||
new_targets = []
|
||||
for equalization_type in ['per_degree_pch_out_db', 'per_degree_psd_out_mWperGHz',
|
||||
'per_degree_psd_out_mWperSlotWidth']:
|
||||
targets = elem[PARAMS_KEY].pop(equalization_type, None)
|
||||
if targets:
|
||||
new_targets.extend([{DEGREE_KEY: degree, equalization_type: target}
|
||||
for degree, target in targets.items()])
|
||||
if new_targets:
|
||||
elem[PARAMS_KEY]['per_degree_power_targets'] = new_targets
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_back_degree(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy yang format back to legacy json topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert back.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: Dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if elem['type'] != ROADM_KEY or PARAMS_KEY not in elem:
|
||||
continue
|
||||
power_targets = elem[PARAMS_KEY].pop('per_degree_power_targets', None)
|
||||
if not power_targets:
|
||||
continue
|
||||
# Process each power target
|
||||
process_power_targets(elem, power_targets)
|
||||
return json_data
|
||||
|
||||
|
||||
def process_power_targets(elem: Dict, power_targets: List[Dict]) -> None:
|
||||
"""Process power targets and update element parameters.
|
||||
|
||||
:param elem: The element to update
|
||||
:type elem: Dict
|
||||
:param power_targets: List of power target configurations
|
||||
:type power_targets: List[Dict]
|
||||
"""
|
||||
equalization_types = [
|
||||
'per_degree_pch_out_db',
|
||||
'per_degree_psd_out_mWperGHz',
|
||||
'per_degree_psd_out_mWperSlotWidth'
|
||||
]
|
||||
|
||||
for target in power_targets:
|
||||
degree_uid = target[DEGREE_KEY]
|
||||
for eq_type in equalization_types:
|
||||
if eq_type not in target:
|
||||
continue
|
||||
# Initialize the equalization type dict if needed
|
||||
if eq_type not in elem[PARAMS_KEY]:
|
||||
elem[PARAMS_KEY][eq_type] = {}
|
||||
# Set the value for this degree
|
||||
elem[PARAMS_KEY][eq_type][degree_uid] = target[eq_type]
|
||||
|
||||
|
||||
def convert_loss_coeff_list(json_data: Dict) -> Dict:
|
||||
"""Convert legacy json topology format to gnpy yang format revision 2025-01-20:
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: Dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if PARAMS_KEY in elem and LOSS_COEF_KEY in elem[PARAMS_KEY] \
|
||||
and isinstance(elem[PARAMS_KEY][LOSS_COEF_KEY], dict):
|
||||
loss_coef_per_frequency = elem[PARAMS_KEY].pop(LOSS_COEF_KEY)
|
||||
loss_coef_list = loss_coef_per_frequency.pop('loss_coef_value', None)
|
||||
frequency_list = loss_coef_per_frequency.pop('frequency', None)
|
||||
if loss_coef_list:
|
||||
new_loss_coef_per_frequency = [{'frequency': f, 'loss_coef_value': v}
|
||||
for f, v in zip(frequency_list, loss_coef_list)]
|
||||
elem[PARAMS_KEY][LOSS_COEF_KEY_PER_FREQ] = new_loss_coef_per_frequency
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_back_loss_coeff_list(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy yang format revision 2025-01-20 back to legacy json topology format
|
||||
|
||||
:param json_data: The input JSON topology data to convert back
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: Dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if PARAMS_KEY in elem and LOSS_COEF_KEY_PER_FREQ in elem[PARAMS_KEY]:
|
||||
loss_coef_per_frequency = elem[PARAMS_KEY].pop(LOSS_COEF_KEY_PER_FREQ)
|
||||
if loss_coef_per_frequency:
|
||||
new_loss_coef_per_frequency = {
|
||||
'frequency': [item['frequency'] for item in loss_coef_per_frequency],
|
||||
'loss_coef_value': [item['loss_coef_value'] for item in loss_coef_per_frequency]}
|
||||
elem[PARAMS_KEY]['loss_coef'] = new_loss_coef_per_frequency
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_design_band(json_data: Dict) -> Dict:
|
||||
"""Convert legacy json topology format to gnpy yang format revision 2025-01-20:
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: Dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if elem['type'] == ROADM_KEY and PARAMS_KEY in elem:
|
||||
new_targets = []
|
||||
targets = elem[PARAMS_KEY].pop('per_degree_design_bands', None)
|
||||
if targets:
|
||||
new_targets.extend([{DEGREE_KEY: degree, 'design_bands': target}
|
||||
for degree, target in targets.items()])
|
||||
if new_targets:
|
||||
elem[PARAMS_KEY]['per_degree_design_bands_targets'] = new_targets
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_back_design_band(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy yang format revision 2025-01-20 back to legacy json topology format
|
||||
|
||||
:param json_data: The input JSON topology data to convert back
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: Dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if elem['type'] == ROADM_KEY and PARAMS_KEY in elem:
|
||||
targets = elem[PARAMS_KEY].pop('per_degree_design_bands_targets', None)
|
||||
if targets:
|
||||
design_bands = {}
|
||||
for target in targets:
|
||||
design_bands[target[DEGREE_KEY]] = target['design_bands']
|
||||
if design_bands:
|
||||
elem[PARAMS_KEY]['per_degree_design_bands'] = design_bands
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_range_to_dict(range_values: List[float]) -> Dict[str, float]:
|
||||
"""Convert a range list to a dictionary format:
|
||||
|
||||
:param range_values: range of loat values defined with the format [min, max, step].
|
||||
:type range_value: List[float]
|
||||
:return: range formatted as a dict {"min_value": min, "max_value": max, "step": step}
|
||||
:rtype: Dict[str, float]
|
||||
"""
|
||||
return {
|
||||
'min_value': range_values[0],
|
||||
'max_value': range_values[1],
|
||||
'step': range_values[2]
|
||||
}
|
||||
|
||||
|
||||
def process_span_data(span: Dict) -> None:
|
||||
"""Convert Span data with range in dict format
|
||||
:param span: The span data to process.
|
||||
:type span: Dict
|
||||
"""
|
||||
if 'delta_power_range_dict_db' in span:
|
||||
return
|
||||
|
||||
if 'delta_power_range_db' not in span:
|
||||
raise KeyError('delta_power_range or delta_power_range_dict_db missing in Span dict.')
|
||||
|
||||
delta_power_range_db = span.get('delta_power_range_db', [0, 0, 0])
|
||||
span['delta_power_range_dict_db'] = convert_range_to_dict(delta_power_range_db)
|
||||
del span['delta_power_range_db']
|
||||
|
||||
|
||||
def process_si_data(si: Dict) -> None:
|
||||
"""Convert Span data with range in dict format
|
||||
:param si: The span data to process.
|
||||
:type si: Dict
|
||||
"""
|
||||
if 'power_range_dict_db' in si:
|
||||
return
|
||||
|
||||
if 'power_range_db' not in si:
|
||||
raise KeyError('power_range_db or power_range_dict_db missing in SI dict.')
|
||||
|
||||
power_range_db = si.get('power_range_db', [0, 0, 0])
|
||||
si['power_range_dict_db'] = convert_range_to_dict(power_range_db)
|
||||
del si['power_range_db']
|
||||
|
||||
|
||||
def convert_delta_power_range(json_data: Dict) -> Dict:
|
||||
"""Convert legacy json equipment format to GNPy yang format revision 2025-01-20
|
||||
|
||||
:param json_data: the input JSON data to convert.
|
||||
:type json_data: Dict
|
||||
:return: The converted JSON data.
|
||||
:rtype: Dict
|
||||
"""
|
||||
if 'Span' in json_data:
|
||||
for span in json_data['Span']:
|
||||
process_span_data(span)
|
||||
|
||||
if 'SI' in json_data:
|
||||
for si in json_data['SI']:
|
||||
process_si_data(si)
|
||||
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_back_delta_power_range(json_data: Dict) -> Dict:
|
||||
"""Convert Yang JSON revision 2025-01-20 equipment format to legacy GNPy format.
|
||||
|
||||
:param json_data: the input JSON data to convert.
|
||||
:type json_data: Dict
|
||||
:return: The converted JSON data.
|
||||
:rtype: Dict
|
||||
"""
|
||||
if 'Span' in json_data and 'delta_power_range_dict_db' in json_data['Span'][0]:
|
||||
delta_power_range_db = json_data['Span'][0]['delta_power_range_dict_db']
|
||||
json_data['Span'][0]['delta_power_range_db'] = [
|
||||
delta_power_range_db['min_value'],
|
||||
delta_power_range_db['max_value'],
|
||||
delta_power_range_db['step']]
|
||||
del json_data['Span'][0]['delta_power_range_dict_db']
|
||||
if 'SI' in json_data and 'power_range_dict_db' in json_data['SI'][0]:
|
||||
power_range_db = json_data['SI'][0]['power_range_dict_db']
|
||||
json_data['SI'][0]['power_range_db'] = [
|
||||
power_range_db['min_value'],
|
||||
power_range_db['max_value'],
|
||||
power_range_db['step']]
|
||||
del json_data['SI'][0]['power_range_dict_db']
|
||||
return json_data
|
||||
|
||||
|
||||
def add_missing_default_type_variety(json_data: Dict) -> Dict:
|
||||
"""Case of ROADM: legacy does not enforce type_variety to be present.
|
||||
This utils ensures that 'default' type_variety is inserted if the key is missing.
|
||||
|
||||
:param json_data: the input JSON data to convert.
|
||||
:type json_data: Dict
|
||||
:return: The converted JSON data.
|
||||
:rtype: Dict
|
||||
"""
|
||||
if 'Roadm' not in json_data:
|
||||
return json_data
|
||||
for i, elem in enumerate(json_data['Roadm']):
|
||||
if 'type_variety' not in elem:
|
||||
# make sure type_variety is the first key in the elem
|
||||
temp = {'type_variety': 'default'}
|
||||
temp.update(elem)
|
||||
json_data['Roadm'][i] = temp
|
||||
break
|
||||
return json_data
|
||||
|
||||
|
||||
def remove_null_region_city(json_data: Dict) -> Dict:
|
||||
"""if present, name should not be None.
|
||||
|
||||
:param json_data: the input JSON data to convert.
|
||||
:type json_data: Dict
|
||||
:return: The converted JSON data.
|
||||
:rtype: Dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if "metadata" in elem and "location" in elem[METADATA_KEY]:
|
||||
for name in ['city', 'region']:
|
||||
if name in elem[METADATA_KEY][LOCATION_KEY] \
|
||||
and elem[METADATA_KEY][LOCATION_KEY][name] is None:
|
||||
elem[METADATA_KEY][LOCATION_KEY][name] = ""
|
||||
return json_data
|
||||
|
||||
|
||||
def remove_union_that_fail(json_data: Dict) -> Dict:
|
||||
"""Convert GNPy legacy JSON request format to GNPy yang format revision 2025-01-20
|
||||
If present "N": or "M": should not contain empy data.
|
||||
If present max-nb-of-channel should not contain empty data.
|
||||
|
||||
:param json_data: the input JSON data to convert.
|
||||
:type json_data: Dict
|
||||
:return: The converted JSON data.
|
||||
:rtype: Dict
|
||||
"""
|
||||
for elem in json_data[PATH_REQUEST_KEY]:
|
||||
te = elem['path-constraints']['te-bandwidth']
|
||||
freq_slot = te.get('effective-freq-slot', None)
|
||||
if freq_slot:
|
||||
for slot in freq_slot:
|
||||
if slot.get('N', None) is None:
|
||||
slot.pop('N', None)
|
||||
if slot.get('M', None) is None:
|
||||
slot.pop('M', None)
|
||||
if not slot:
|
||||
te['effective-freq-slot'].remove(slot)
|
||||
if not te['effective-freq-slot']:
|
||||
te.pop('effective-freq-slot', None)
|
||||
for attribute in ['max-nb-of-channel', 'trx_mode', 'output-power']:
|
||||
if te.get(attribute) is None:
|
||||
te.pop(attribute, None)
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_none_to_empty(json_data: Any):
|
||||
"""Convert all instances of None in the input to [None].
|
||||
|
||||
This function recursively traverses the input and replaces any None
|
||||
values with a list containing None. If the input is already a list
|
||||
containing None, it returns the input unchanged.
|
||||
|
||||
:param json_data: The input data to process, which can be of any type.
|
||||
:type json_data: Any
|
||||
:return: A new representation of the input with None values replaced by [None].
|
||||
:rtype: Any
|
||||
|
||||
:example:
|
||||
>>> a = {'uid': '[930/WRT-2-2-SIG=>923/WRT-1-9-SIG]-923/AMP-1-13', 'type_variety': 'AMP',
|
||||
... 'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}},
|
||||
... 'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'AMP_LOW_C',
|
||||
... 'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0,
|
||||
... 'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'AMP_LOW_L',
|
||||
... 'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0,
|
||||
... 'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
>>> convert_none_to_empty(a)
|
||||
{'uid': '[930/WRT-2-2-SIG=>923/WRT-1-9-SIG]-923/AMP-1-13', 'type_variety': 'AMP', \
|
||||
'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}}, \
|
||||
'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'AMP_LOW_C', \
|
||||
'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': [None], 'tilt_target': 0.0, \
|
||||
'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'AMP_LOW_L', \
|
||||
'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': [None], 'tilt_target': 0.0, \
|
||||
'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
|
||||
"""
|
||||
if json_data == [None]:
|
||||
# already conformed
|
||||
return json_data
|
||||
if isinstance(json_data, dict):
|
||||
for key, value in json_data.items():
|
||||
json_data[key] = convert_none_to_empty(value)
|
||||
elif isinstance(json_data, list):
|
||||
for i, elem in enumerate(json_data):
|
||||
json_data[i] = convert_none_to_empty(elem)
|
||||
elif json_data is None:
|
||||
return [None]
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_empty_to_none(json_data: Any):
|
||||
"""Convert all instances of [None] in the input to None.
|
||||
|
||||
This function recursively traverses the input data and replaces any
|
||||
lists containing a single None element with None. If the input is
|
||||
already None, it returns None unchanged.
|
||||
|
||||
:param json_data: The input data to process, which can be of any type.
|
||||
:type json_data: Any
|
||||
:return: A new representation of the input with [None] replaced by None.
|
||||
:rtype: Any
|
||||
|
||||
>>> json_data = {
|
||||
... "uid": "[930/WRT-2-2-SIG=>923/WRT-1-9-SIG]-923/AMP-1-13",
|
||||
... "type_variety": "AMP",
|
||||
... "metadata": {
|
||||
... "location": {
|
||||
... "latitude": 0.000000,
|
||||
... "longitude": 0.000000,
|
||||
... "city": "Zion",
|
||||
... "region": ""
|
||||
... }
|
||||
... },
|
||||
... "type": "Multiband_amplifier",
|
||||
... "amplifiers": [{
|
||||
... "type_variety": "AMP_LOW_C",
|
||||
... "operational": {
|
||||
... "gain_target": 12.22,
|
||||
... "delta_p": 4.19,
|
||||
... "out_voa": [None],
|
||||
... "tilt_target": 0.00,
|
||||
... "f_min": 191.3,
|
||||
... "f_max": 196.1
|
||||
... }
|
||||
... }, {
|
||||
... "type_variety": "AMP_LOW_L",
|
||||
... "operational": {
|
||||
... "gain_target": 12.05,
|
||||
... "delta_p": 4.19,
|
||||
... "out_voa": [None],
|
||||
... "tilt_target": 0.00,
|
||||
... "f_min": 186.1,
|
||||
... "f_max": 190.9
|
||||
... }
|
||||
... }
|
||||
... ]
|
||||
... }
|
||||
>>> convert_empty_to_none(json_data)
|
||||
{'uid': '[930/WRT-2-2-SIG=>923/WRT-1-9-SIG]-923/AMP-1-13', 'type_variety': 'AMP', \
|
||||
'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}}, \
|
||||
'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'AMP_LOW_C', \
|
||||
'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0, \
|
||||
'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'AMP_LOW_L', \
|
||||
'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0, \
|
||||
'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
|
||||
"""
|
||||
if isinstance(json_data, dict):
|
||||
for key, value in json_data.items():
|
||||
json_data[key] = convert_empty_to_none(value)
|
||||
elif isinstance(json_data, list):
|
||||
if len(json_data) == 1 and json_data[0] is None:
|
||||
return None
|
||||
for i, elem in enumerate(json_data):
|
||||
json_data[i] = convert_empty_to_none(elem)
|
||||
return json_data
|
||||
|
||||
|
||||
def remove_namespace_context(json_data: Union[Dict, List, float, int, str, bool, None], namespace: str) \
|
||||
-> Union[Dict, List, float, int, str, bool, None]:
|
||||
"""Serialisation with yang introduces a namespace in values that
|
||||
are defined as identity. this function filter them out.
|
||||
|
||||
:param json_data: The input JSON topology data to process.
|
||||
:type json_data: Union[Dict, List, float, int, str, bool, None]
|
||||
:param namespace: a namespace string
|
||||
:type namespace: str
|
||||
:return: the converted JSON data
|
||||
:rtype: Union[Dict, List, float, int, str, bool, None]
|
||||
|
||||
>>> a = [{"a": 123, "b": "123:alkdje"}, {"a": 456, "c": "123", "d": "123:123"}]
|
||||
>>> remove_namespace_context(a, "123:")
|
||||
[{'a': 123, 'b': 'alkdje'}, {'a': 456, 'c': '123', 'd': '123'}]
|
||||
|
||||
"""
|
||||
if isinstance(json_data, dict):
|
||||
for key, value in json_data.items():
|
||||
json_data[key] = remove_namespace_context(value, namespace)
|
||||
elif isinstance(json_data, list):
|
||||
for i, elem in enumerate(json_data):
|
||||
json_data[i] = remove_namespace_context(elem, namespace)
|
||||
elif isinstance(json_data, str) and namespace in json_data:
|
||||
return json_data.split(namespace)[1]
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_nf_coef(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy legacy format yang topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
if 'Edfa' not in json_data:
|
||||
return json_data
|
||||
for edfa in json_data['Edfa']:
|
||||
if 'nf_coef' in edfa and not isinstance(edfa['nf_coef'][0], dict):
|
||||
nf_coef = edfa.pop('nf_coef')
|
||||
new_nf_coef = [{'coef_order': i, 'nf_coef': c} for i, c in enumerate(nf_coef)]
|
||||
edfa['nf_coef'] = new_nf_coef
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_back_nf_coef(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy yang format back to legacy json topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert back.
|
||||
:type json_data: Dict
|
||||
:return: the converted back JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
if 'Edfa' not in json_data:
|
||||
return json_data
|
||||
for edfa in json_data['Edfa']:
|
||||
if 'nf_coef' in edfa and isinstance(edfa['nf_coef'][0], dict):
|
||||
nf_coef = edfa.pop('nf_coef')
|
||||
sorted_nf_coef = sorted(nf_coef, key=lambda x: x['coef_order'])
|
||||
new_nf_coef = [c['nf_coef'] for c in sorted_nf_coef]
|
||||
edfa['nf_coef'] = new_nf_coef
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_nf_fit_coef(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy legacy format yang topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
if 'nf_fit_coeff' in json_data and not isinstance(json_data['nf_fit_coeff'][0], dict):
|
||||
nf_coef = json_data.pop('nf_fit_coeff')
|
||||
new_nf_coef = [{'coef_order': i, 'nf_coef': c} for i, c in enumerate(nf_coef)]
|
||||
json_data['nf_fit_coeff'] = new_nf_coef
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_back_nf_fit_coef(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy yang format back to legacy json topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert back.
|
||||
:type json_data: Dict
|
||||
:return: the converted back JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
if 'nf_fit_coeff' in json_data and isinstance(json_data['nf_fit_coeff'][0], dict):
|
||||
nf_coef = json_data.pop('nf_fit_coeff')
|
||||
sorted_nf_coef = sorted(nf_coef, key=lambda x: x['coef_order'])
|
||||
new_nf_coef = [c['nf_coef'] for c in sorted_nf_coef]
|
||||
json_data['nf_fit_coeff'] = new_nf_coef
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_raman_coef(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy legacy format yang topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if PARAMS_KEY in elem and RAMAN_COEF_KEY in elem[PARAMS_KEY] \
|
||||
and 'g0' in elem[PARAMS_KEY][RAMAN_COEF_KEY]:
|
||||
raman_coef = elem[PARAMS_KEY].pop(RAMAN_COEF_KEY)
|
||||
g0_list = raman_coef.pop('g0', [])
|
||||
frequency_offset_list = raman_coef.pop('frequency_offset', [])
|
||||
if frequency_offset_list:
|
||||
new_raman_coef = {'reference_frequency': raman_coef['reference_frequency'],
|
||||
'g0_per_frequency': [{'frequency_offset': f, 'g0': v}
|
||||
for f, v in zip(frequency_offset_list, g0_list)]}
|
||||
elem[PARAMS_KEY][RAMAN_COEF_KEY] = new_raman_coef
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_back_raman_coef(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy yang format back to legacy json topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert back.
|
||||
:type json_data: Dict
|
||||
:return: the converted back JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
for elem in json_data[ELEMENTS_KEY]:
|
||||
if PARAMS_KEY in elem and RAMAN_COEF_KEY in elem[PARAMS_KEY] \
|
||||
and 'g0_per_frequency' in elem[PARAMS_KEY][RAMAN_COEF_KEY]:
|
||||
raman_coef = elem[PARAMS_KEY].pop(RAMAN_COEF_KEY)
|
||||
g0_list = [g['g0'] for g in raman_coef.pop('g0_per_frequency', [])]
|
||||
frequency_offset_list = [f['frequency_offset'] for f in raman_coef.pop('g0_per_frequency', [])]
|
||||
if frequency_offset_list:
|
||||
new_raman_coef = {'reference_frequency': raman_coef['reference_frequency'],
|
||||
'g0': g0_list,
|
||||
'frequency_offset': frequency_offset_list}
|
||||
elem[PARAMS_KEY][RAMAN_COEF_KEY] = new_raman_coef
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_raman_efficiency(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy legacy format yang topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
if 'RamanFiber' not in json_data:
|
||||
return json_data
|
||||
for fiber_eqpt in json_data['RamanFiber']:
|
||||
if RAMAN_EFFICIENCY_KEY in fiber_eqpt \
|
||||
and 'cr' in fiber_eqpt[RAMAN_EFFICIENCY_KEY]:
|
||||
raman_efficiency = fiber_eqpt.pop(RAMAN_EFFICIENCY_KEY)
|
||||
cr_list = raman_efficiency.pop('cr', [])
|
||||
frequency_offset_list = raman_efficiency.pop('frequency_offset', [])
|
||||
if frequency_offset_list:
|
||||
new_raman_efficiency = [{'frequency_offset': f, 'cr': v}
|
||||
for f, v in zip(frequency_offset_list, cr_list)]
|
||||
fiber_eqpt[RAMAN_EFFICIENCY_KEY] = new_raman_efficiency
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_back_raman_efficiency(json_data: Dict) -> Dict:
|
||||
"""Convert gnpy yang format back to legacy json topology format.
|
||||
|
||||
:param json_data: The input JSON topology data to convert back.
|
||||
:type json_data: Dict
|
||||
:return: the converted back JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
if 'RamanFiber' not in json_data:
|
||||
return json_data
|
||||
for fiber_eqpt in json_data['RamanFiber']:
|
||||
if RAMAN_EFFICIENCY_KEY in fiber_eqpt and isinstance(fiber_eqpt[RAMAN_EFFICIENCY_KEY], list):
|
||||
raman_efficiency = fiber_eqpt.pop(RAMAN_EFFICIENCY_KEY)
|
||||
cr_list = [c['cr'] for c in raman_efficiency]
|
||||
frequency_offset_list = [f['frequency_offset'] for f in raman_efficiency]
|
||||
if frequency_offset_list:
|
||||
old_raman_efficiency = {'cr': cr_list,
|
||||
'frequency_offset': frequency_offset_list}
|
||||
fiber_eqpt[RAMAN_COEF_KEY] = old_raman_efficiency
|
||||
return json_data
|
||||
|
||||
|
||||
def reorder_keys(data_list: List, key: str) -> List:
|
||||
"""Roarder item in a dict placing the key (the key of a list with YANG meaning) first.
|
||||
This is required because oopt-gnpy-libyang does not recognize the key when it is not placed first in the data node.
|
||||
|
||||
:param json_data: the list of dictionary items.
|
||||
:type data_list: List
|
||||
:return: the converted back JSON data
|
||||
:rtype: List
|
||||
"""
|
||||
for item in data_list:
|
||||
index_value = item.pop(key, None)
|
||||
if index_value is not None:
|
||||
# Place key first
|
||||
new_item = {key: index_value}
|
||||
# add other items
|
||||
new_item.update(item)
|
||||
# replace old element with new element
|
||||
for k in list(item.keys()):
|
||||
item.pop(k)
|
||||
item.update(new_item)
|
||||
return data_list
|
||||
|
||||
|
||||
# next functions because ly requires that the key of a list be in the first position in the item
|
||||
def reorder_route_objects(json_data: Dict) -> Dict:
|
||||
"""Make sure that the index of a route object is placed first in the object.
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
for request in json_data['path-request']:
|
||||
if "explicit-route-objects" in request:
|
||||
request["explicit-route-objects"]["route-object-include-exclude"] = \
|
||||
reorder_keys(request["explicit-route-objects"]["route-object-include-exclude"], "index")
|
||||
return json_data
|
||||
|
||||
|
||||
def reorder_lumped_losses_objects(json_data: Dict) -> Dict:
|
||||
"""Make sure that the position of a lumped loss object is placed first in the object.
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
for element in json_data['elements']:
|
||||
if "params" in element and "lumped_losses" in element["params"]:
|
||||
element["params"]["lumped_losses"] = reorder_keys(element["params"]["lumped_losses"], "position")
|
||||
return json_data
|
||||
|
||||
|
||||
def reorder_raman_pumps(json_data: Dict) -> Dict:
|
||||
"""Make sure that the frequency of a Raman pum object is placed first in the object.
|
||||
|
||||
:param json_data: The input JSON topology data to convert.
|
||||
:type json_data: Dict
|
||||
:return: the converted JSON data
|
||||
:rtype: dict
|
||||
"""
|
||||
for element in json_data['elements']:
|
||||
if "operational" in element and "raman_pumps" in element["operational"]:
|
||||
element["operational"]["raman_pumps"] = reorder_keys(element["operational"]["raman_pumps"], "frequency")
|
||||
return json_data
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.topology.request: path computation functionality
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.topology.request
|
||||
=====================
|
||||
@@ -16,27 +21,34 @@ See: draft-ietf-teas-yang-path-computation-01.txt
|
||||
"""
|
||||
|
||||
from collections import namedtuple, OrderedDict
|
||||
from typing import List
|
||||
from logging import getLogger
|
||||
from networkx import (dijkstra_path, NetworkXNoPath,
|
||||
all_simple_paths, shortest_simple_paths)
|
||||
from networkx.utils import pairwise
|
||||
from numpy import mean, argmin
|
||||
from gnpy.core.elements import Transceiver, Roadm
|
||||
from gnpy.core.utils import lin2db
|
||||
from gnpy.core.info import create_input_spectral_information, carriers_to_spectral_information
|
||||
|
||||
from gnpy.core.elements import Transceiver, Roadm, Edfa, Multiband_amplifier
|
||||
from gnpy.core.utils import lin2db, unique_ordered, find_common_range
|
||||
from gnpy.core.info import create_input_spectral_information, carriers_to_spectral_information, \
|
||||
demuxed_spectral_information, muxed_spectral_information, SpectralInformation
|
||||
from gnpy.core import network as network_module
|
||||
from gnpy.core.exceptions import ServiceError, DisjunctionError
|
||||
from copy import deepcopy
|
||||
from csv import writer
|
||||
from math import ceil
|
||||
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
|
||||
|
||||
RequestParams = namedtuple('RequestParams', 'request_id source destination bidir trx_type'
|
||||
' trx_mode nodes_list loose_list spacing power nb_channel f_min'
|
||||
' f_max format baud_rate OSNR penalties bit_rate'
|
||||
' roll_off tx_osnr min_spacing cost path_bandwidth effective_freq_slot'
|
||||
' equalization_offset_db, tx_power')
|
||||
|
||||
|
||||
DisjunctionParams = namedtuple('DisjunctionParams', 'disjunction_id relaxable link_diverse'
|
||||
' node_diverse disjunctions_req')
|
||||
|
||||
@@ -298,7 +310,9 @@ def compute_constrained_path(network, req):
|
||||
nodes_list = []
|
||||
for node in req.nodes_list[:-1]:
|
||||
nodes_list.append(next(el for el in network if el.uid == node))
|
||||
|
||||
total_path = explicit_path(nodes_list, source, destination, network)
|
||||
if total_path is not None:
|
||||
return total_path
|
||||
try:
|
||||
path_generator = shortest_simple_paths(network, source, destination, weight='weight')
|
||||
total_path = next(path for path in path_generator if ispart(nodes_list, path))
|
||||
@@ -332,19 +346,40 @@ def compute_constrained_path(network, req):
|
||||
return total_path
|
||||
|
||||
|
||||
def filter_si(path: list, equipment: dict, si: SpectralInformation) -> SpectralInformation:
|
||||
"""Filter spectral information based on the amplifiers common range"""
|
||||
# First retrieve f_min, f_max spectrum according to amplifiers' spectrum on the path
|
||||
common_range = find_elements_common_range(path, equipment)
|
||||
# filter out frequencies that should not be created
|
||||
filtered_si = []
|
||||
for band in common_range:
|
||||
temp = demuxed_spectral_information(si, band)
|
||||
if temp:
|
||||
filtered_si.append(temp)
|
||||
if not filtered_si:
|
||||
raise ValueError('Defined propagation band does not match amplifiers band.')
|
||||
return muxed_spectral_information(filtered_si)
|
||||
|
||||
|
||||
def propagate(path, req, equipment):
|
||||
"""propagates signals in each element according to initial spectrum set by user"""
|
||||
"""propagates signals in each element according to initial spectrum set by user
|
||||
Spectrum is specified in request through f_min, f_max and spacing, or initial_spectrum
|
||||
and amps frequency band on the path is used to filter out frequencies"""
|
||||
# generates spectrum based on request
|
||||
if req.initial_spectrum is not None:
|
||||
si = carriers_to_spectral_information(initial_spectrum=req.initial_spectrum, power=req.power)
|
||||
else:
|
||||
si = create_input_spectral_information(
|
||||
f_min=req.f_min, f_max=req.f_max, roll_off=req.roll_off, baud_rate=req.baud_rate,
|
||||
spacing=req.spacing, tx_osnr=req.tx_osnr, tx_power=req.tx_power, delta_pdb=req.offset_db)
|
||||
# filter out frequencies that should not be created
|
||||
si = filter_si(path, equipment, si)
|
||||
roadm_osnr = []
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
si = el(si, degree=path[i + 1].uid, from_degree=path[i - 1].uid)
|
||||
roadm_osnr.append(el.get_roadm_path(from_degree=path[i - 1].uid, to_degree=path[i + 1].uid).impairment.osnr)
|
||||
roadm_osnr.append(el.get_impairment('roadm-osnr', si.frequency,
|
||||
from_degree=path[i - 1].uid, degree=path[i + 1].uid))
|
||||
else:
|
||||
si = el(si)
|
||||
path[0].update_snr(si.tx_osnr)
|
||||
@@ -354,7 +389,6 @@ def propagate(path, req, equipment):
|
||||
path[-1].calc_penalties(req.penalties)
|
||||
return si
|
||||
|
||||
|
||||
def propagate_and_optimize_mode(path, req, equipment):
|
||||
# if mode is unknown : loops on the modes starting from the highest baudrate fiting in the
|
||||
# step 1: create an ordered list of modes based on baudrate and power offset
|
||||
@@ -385,11 +419,13 @@ def propagate_and_optimize_mode(path, req, equipment):
|
||||
baud_rate=this_br, spacing=req.spacing,
|
||||
delta_pdb=this_offset, tx_osnr=req.tx_osnr,
|
||||
tx_power=req.tx_power)
|
||||
spc_info = filter_si(path, equipment, spc_info)
|
||||
roadm_osnr = []
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
spc_info = el(spc_info, degree=path[i + 1].uid, from_degree=path[i - 1].uid)
|
||||
roadm_osnr.append(el.get_roadm_path(from_degree=path[i - 1].uid, to_degree=path[i + 1].uid).impairment.osnr)
|
||||
roadm_osnr.append(el.get_impairment('roadm-osnr', spc_info.frequency,
|
||||
from_degree=path[i - 1].uid, degree=path[i + 1].uid))
|
||||
else:
|
||||
spc_info = el(spc_info)
|
||||
for this_mode in modes_to_explore:
|
||||
@@ -1071,7 +1107,7 @@ def deduplicate_disjunctions(disjn):
|
||||
return local_disjn
|
||||
|
||||
|
||||
def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
||||
def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist, redesign=False):
|
||||
"""use a list but a dictionnary might be helpful to find path based on request_id
|
||||
|
||||
TODO change all these req, dsjct, res lists into dict !
|
||||
@@ -1080,6 +1116,10 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
||||
reversed_path_res_list = []
|
||||
propagated_reversed_path_res_list = []
|
||||
|
||||
total_nb_requests = len(pathreqlist)
|
||||
if redesign:
|
||||
LOGGER.warning('Redesign the network for each request channel, '
|
||||
+ 'using the request channel as the reference channel for the design.')
|
||||
for i, pathreq in enumerate(pathreqlist):
|
||||
|
||||
# use the power specified in requests but might be different from the one
|
||||
@@ -1097,7 +1137,16 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
||||
# 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
|
||||
network_module.design_network(pathreq, network, equipment, set_connector_losses=False, verbose=False)
|
||||
# reversed path is needed for correct spectrum assignment
|
||||
if redesign:
|
||||
# this is the legacy case where network was automatically redesigned using the
|
||||
# request channel as reference (nb and power used for amplifiers total power out)
|
||||
reversed_path = []
|
||||
if pathlist[i]:
|
||||
reversed_path = find_reversed_path(pathlist[i])
|
||||
network_nodes_for_redesign = pathlist[i] + reversed_path
|
||||
network_module.design_network(pathreq, network.subgraph(network_nodes_for_redesign), equipment,
|
||||
set_connector_losses=False, verbose=False)
|
||||
total_path = deepcopy(pathlist[i])
|
||||
msg = msg + f'\n\tComputed path (roadms):{[e.uid for e in total_path if isinstance(e, Roadm)]}'
|
||||
LOGGER.info(msg)
|
||||
@@ -1137,6 +1186,7 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
||||
pathreq.tx_osnr = mode['tx_osnr']
|
||||
pathreq.bit_rate = mode['bit_rate']
|
||||
pathreq.penalties = mode['penalties']
|
||||
pathreq.offset_db = mode['equalization_offset_db']
|
||||
# other blocking reason should not appear at this point
|
||||
except AttributeError:
|
||||
pathreq.baud_rate = mode['baud_rate']
|
||||
@@ -1146,6 +1196,7 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
||||
pathreq.tx_osnr = mode['tx_osnr']
|
||||
pathreq.bit_rate = mode['bit_rate']
|
||||
pathreq.penalties = mode['penalties']
|
||||
pathreq.offset_db = mode['equalization_offset_db']
|
||||
|
||||
# reversed path is needed for correct spectrum assignment
|
||||
reversed_path = find_reversed_path(pathlist[i])
|
||||
@@ -1212,3 +1263,50 @@ def _penalty_msg(total_path, msg, min_ind):
|
||||
else:
|
||||
msg += f'\n\t{pretty} penalty not evaluated'
|
||||
return msg
|
||||
|
||||
|
||||
def is_adjacent(oms1, oms2):
|
||||
""" oms1's egress ROADM is oms2's ingress ROADM
|
||||
"""
|
||||
return oms1.el_list[-1] == oms2.el_list[0]
|
||||
|
||||
|
||||
def explicit_path(node_list, source, destination, network):
|
||||
""" if list of nodes leads to adjacent oms, then means that the path is explicit, and no need to compute
|
||||
the function returns the explicit path (including source and destination ROADMs)
|
||||
"""
|
||||
path_oms = []
|
||||
for elem in node_list:
|
||||
if hasattr(elem, 'oms'):
|
||||
path_oms.append(elem.oms)
|
||||
if not path_oms:
|
||||
return None
|
||||
path_oms = unique_ordered(path_oms)
|
||||
try:
|
||||
next_node = next(network.successors(source))
|
||||
source_roadm = next_node if isinstance(next_node, Roadm) else source
|
||||
previous_node = next(network.predecessors(destination))
|
||||
destination_roadm = previous_node if isinstance(previous_node, Roadm) else destination
|
||||
if not (path_oms[0].el_list[0] == source_roadm and path_oms[-1].el_list[-1] == destination_roadm):
|
||||
return None
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
oms0 = path_oms[0]
|
||||
path = [source] + oms0.el_list
|
||||
for oms in path_oms[1:]:
|
||||
if not is_adjacent(oms0, oms):
|
||||
return None
|
||||
oms0 = oms
|
||||
path.extend(oms.el_list)
|
||||
path.append(destination)
|
||||
return unique_ordered(path)
|
||||
|
||||
|
||||
def find_elements_common_range(el_list: list, equipment: dict) -> List[dict]:
|
||||
"""Find the common frequency range of amps of a given list of elements (for example an OMS or a path)
|
||||
If there are no amplifiers in the path, then use the SI
|
||||
"""
|
||||
amp_bands = [n.params.bands for n in el_list if isinstance(n, (Edfa, Multiband_amplifier))]
|
||||
return find_common_range(amp_bands, equipment['SI']['default'].f_min, equipment['SI']['default'].f_max,
|
||||
equipment['SI']['default'].spacing)
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.topology.spectrum_assignment: spectrum assignment functionality
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.topology.spectrum_assignment
|
||||
=================================
|
||||
@@ -15,28 +20,31 @@ element/oms correspondace
|
||||
|
||||
from collections import namedtuple
|
||||
from logging import getLogger
|
||||
from gnpy.core.elements import Roadm, Transceiver
|
||||
|
||||
from gnpy.core.elements import Roadm, Transceiver, Edfa, Multiband_amplifier
|
||||
from gnpy.core.exceptions import ServiceError, SpectrumError
|
||||
from gnpy.core.utils import order_slots, restore_order
|
||||
from gnpy.topology.request import compute_spectrum_slot_vs_bandwidth
|
||||
from gnpy.topology.request import compute_spectrum_slot_vs_bandwidth, find_elements_common_range
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
GUARDBAND = 25e9
|
||||
|
||||
|
||||
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
|
||||
def __init__(self, f_min, f_max, grid, guardband=GUARDBAND, bitmap=None):
|
||||
# n is the min index including guardband. Guardband is required 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
|
||||
n_min = frequency_to_n(f_min, grid)
|
||||
n_max = frequency_to_n(f_max, grid)
|
||||
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_min = frequency_to_n(f_min + guardband)
|
||||
self.freq_index_max = frequency_to_n(f_max - guardband)
|
||||
self.freq_index = list(range(n_min, n_max + 1))
|
||||
self.guardband = guardband
|
||||
if bitmap is None:
|
||||
self.bitmap = [1] * (n_max - n_min + 1)
|
||||
elif len(bitmap) == len(self.freq_index):
|
||||
@@ -83,7 +91,6 @@ class OMS:
|
||||
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}',
|
||||
@@ -98,7 +105,7 @@ class OMS:
|
||||
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):
|
||||
def update_spectrum(self, f_min, f_max, guardband=GUARDBAND, existing_spectrum=None, grid=0.00625e12):
|
||||
"""Frequencies expressed in Hz.
|
||||
Add 150 GHz margin to enable a center channel on f_min
|
||||
Use ITU-T G694.1 Flexible DWDM grid definition
|
||||
@@ -226,6 +233,40 @@ def align_grids(oms_list):
|
||||
return oms_list
|
||||
|
||||
|
||||
def find_network_freq_range(network, equipment):
|
||||
"""Find the lowest freq from amps and highest freq among all amps to determine the resulting bitmap
|
||||
"""
|
||||
amp_bands = [band for n in network.nodes() if isinstance(n, (Edfa, Multiband_amplifier)) for band in n.params.bands]
|
||||
min_frequencies = [a['f_min'] for a in amp_bands]
|
||||
max_frequencies = [a['f_max'] for a in amp_bands]
|
||||
return min(min_frequencies), max(max_frequencies)
|
||||
|
||||
|
||||
def create_oms_bitmap(oms, equipment, f_min, f_max, guardband, grid):
|
||||
"""Find the highest low freq from oms amps and lowest high freq among oms amps to determine
|
||||
the possible bitmap window.
|
||||
f_min and f_max represent the useable spectrum (not the useable center frequencies)
|
||||
ie n smaller than frequency_to_n(min_freq, grid) are not useable
|
||||
"""
|
||||
n_min = frequency_to_n(f_min, grid)
|
||||
n_max = frequency_to_n(f_max, grid) - 1
|
||||
common_range = find_elements_common_range(oms.el_list, equipment)
|
||||
band0 = common_range[0]
|
||||
band0_n_min = frequency_to_n(band0['f_min'], grid)
|
||||
band0_n_max = frequency_to_n(band0['f_max'], grid)
|
||||
bitmap = [0] * (band0_n_min - n_min) + [1] * (band0_n_max - band0_n_min + 1)
|
||||
i = 1
|
||||
while i < len(common_range):
|
||||
band = common_range[i]
|
||||
band_n_min = frequency_to_n(band['f_min'], grid)
|
||||
band_n_max = frequency_to_n(band['f_max'], grid)
|
||||
bitmap = bitmap + [0] * (band_n_min - band0_n_max - 1) + [1] * (band_n_max - band_n_min + 1)
|
||||
band0_n_max = band_n_max
|
||||
i += 1
|
||||
bitmap = bitmap + [0] * (n_max - band0_n_max)
|
||||
return bitmap
|
||||
|
||||
|
||||
def build_oms_list(network, equipment):
|
||||
"""initialization of OMS list in the network
|
||||
|
||||
@@ -237,7 +278,15 @@ def build_oms_list(network, equipment):
|
||||
"""
|
||||
oms_id = 0
|
||||
oms_list = []
|
||||
for node in [n for n in network.nodes() if isinstance(n, Roadm)]:
|
||||
# identify all vertices of OMS: of course ROADM, but aso links to external chassis transponders
|
||||
oms_vertices = [n for n in network.nodes() if isinstance(n, Roadm)] +\
|
||||
[n for n in network.nodes() if isinstance(n, Transceiver)
|
||||
and not isinstance(next(network.successors(n)), Roadm)]
|
||||
# determine the size of the bitmap common to all the omses: find min and max frequencies of all amps
|
||||
# in the network. These gives the band not the center frequency. Thhen we use a reference channel
|
||||
# slot width (50GHz) to set the f_min, f_max
|
||||
f_min, f_max = find_network_freq_range(network, equipment)
|
||||
for node in oms_vertices:
|
||||
for edge in network.edges([node]):
|
||||
if not isinstance(edge[1], Transceiver):
|
||||
nd_in = edge[0] # nd_in is a Roadm
|
||||
@@ -271,8 +320,9 @@ def build_oms_list(network, equipment):
|
||||
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)
|
||||
bitmap = create_oms_bitmap(oms, equipment, f_min=f_min, f_max=f_max, guardband=GUARDBAND,
|
||||
grid=0.00625e12)
|
||||
oms.update_spectrum(f_min, f_max, guardband=GUARDBAND, grid=0.00625e12, existing_spectrum=bitmap)
|
||||
# oms.assign_spectrum(13,7) gives back (193137500000000.0, 193225000000000.0)
|
||||
# as in the example in the standard
|
||||
# oms.assign_spectrum(13,7)
|
||||
@@ -333,10 +383,11 @@ def aggregate_oms_bitmap(path_oms, oms_list):
|
||||
'el_id_list': 0,
|
||||
'el_list': []
|
||||
}
|
||||
freq_min = nvalue_to_frequency(spectrum.freq_index_min)
|
||||
freq_max = nvalue_to_frequency(spectrum.freq_index_max)
|
||||
freq_min = nvalue_to_frequency(spectrum.n_min)
|
||||
freq_max = nvalue_to_frequency(spectrum.n_max)
|
||||
aggregate_oms = OMS(**params)
|
||||
aggregate_oms.update_spectrum(freq_min, freq_max, grid=0.00625e12, existing_spectrum=bitmap)
|
||||
aggregate_oms.update_spectrum(freq_min, freq_max, grid=0.00625e12, guardband=spectrum.guardband,
|
||||
existing_spectrum=bitmap)
|
||||
return aggregate_oms
|
||||
|
||||
|
||||
|
||||
2241
gnpy/yang/ext/ietf-layer0-types.yang
Normal file
2241
gnpy/yang/ext/ietf-layer0-types.yang
Normal file
File diff suppressed because it is too large
Load Diff
2247
gnpy/yang/ext/ietf-layer0-types@2024-03-04.yang
Normal file
2247
gnpy/yang/ext/ietf-layer0-types@2024-03-04.yang
Normal file
File diff suppressed because it is too large
Load Diff
294
gnpy/yang/ext/ietf-network-topology@2018-02-26.yang
Normal file
294
gnpy/yang/ext/ietf-network-topology@2018-02-26.yang
Normal file
@@ -0,0 +1,294 @@
|
||||
module ietf-network-topology {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-network-topology";
|
||||
prefix nt;
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
import ietf-network {
|
||||
prefix nw;
|
||||
reference
|
||||
"RFC 8345: A YANG Data Model for Network Topologies";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF I2RS (Interface to the Routing System) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/i2rs/>
|
||||
WG List: <mailto:i2rs@ietf.org>
|
||||
|
||||
Editor: Alexander Clemm
|
||||
<mailto:ludwig@clemm.org>
|
||||
|
||||
Editor: Jan Medved
|
||||
<mailto:jmedved@cisco.com>
|
||||
|
||||
Editor: Robert Varga
|
||||
<mailto:robert.varga@pantheon.tech>
|
||||
|
||||
Editor: Nitin Bahadur
|
||||
<mailto:nitin_bahadur@yahoo.com>
|
||||
|
||||
Editor: Hariharan Ananthakrishnan
|
||||
<mailto:hari@packetdesign.com>
|
||||
|
||||
Editor: Xufeng Liu
|
||||
<mailto:xufeng.liu.ietf@gmail.com>";
|
||||
|
||||
description
|
||||
"This module defines a common base model for a network topology,
|
||||
augmenting the base network data model with links to connect
|
||||
nodes, as well as termination points to terminate links
|
||||
on nodes.
|
||||
|
||||
Copyright (c) 2018 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8345;
|
||||
see the RFC itself for full legal notices.";
|
||||
|
||||
revision 2018-02-26 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 8345: A YANG Data Model for Network Topologies";
|
||||
}
|
||||
|
||||
typedef link-id {
|
||||
type inet:uri;
|
||||
description
|
||||
"An identifier for a link in a topology. The precise
|
||||
structure of the link-id will be up to the implementation.
|
||||
The identifier SHOULD be chosen such that the same link in a
|
||||
real network topology will always be identified through the
|
||||
same identifier, even if the data model is instantiated in
|
||||
separate datastores. An implementation MAY choose to capture
|
||||
semantics in the identifier -- for example, to indicate the
|
||||
type of link and/or the type of topology of which the link is
|
||||
a part.";
|
||||
}
|
||||
|
||||
typedef tp-id {
|
||||
type inet:uri;
|
||||
description
|
||||
"An identifier for termination points on a node. The precise
|
||||
structure of the tp-id will be up to the implementation.
|
||||
The identifier SHOULD be chosen such that the same termination
|
||||
point in a real network topology will always be identified
|
||||
through the same identifier, even if the data model is
|
||||
instantiated in separate datastores. An implementation MAY
|
||||
choose to capture semantics in the identifier -- for example,
|
||||
to indicate the type of termination point and/or the type of
|
||||
node that contains the termination point.";
|
||||
}
|
||||
|
||||
grouping link-ref {
|
||||
description
|
||||
"This grouping can be used to reference a link in a specific
|
||||
network. Although it is not used in this module, it is
|
||||
defined here for the convenience of augmenting modules.";
|
||||
leaf link-ref {
|
||||
type leafref {
|
||||
path "/nw:networks/nw:network[nw:network-id=current()/../"+
|
||||
"network-ref]/nt:link/nt:link-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"A type for an absolute reference to a link instance.
|
||||
(This type should not be used for relative references.
|
||||
In such a case, a relative path should be used instead.)";
|
||||
}
|
||||
uses nw:network-ref;
|
||||
}
|
||||
|
||||
grouping tp-ref {
|
||||
description
|
||||
"This grouping can be used to reference a termination point
|
||||
in a specific node. Although it is not used in this module,
|
||||
it is defined here for the convenience of augmenting
|
||||
modules.";
|
||||
leaf tp-ref {
|
||||
type leafref {
|
||||
path "/nw:networks/nw:network[nw:network-id=current()/../"+
|
||||
"network-ref]/nw:node[nw:node-id=current()/../"+
|
||||
"node-ref]/nt:termination-point/nt:tp-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"A type for an absolute reference to a termination point.
|
||||
(This type should not be used for relative references.
|
||||
In such a case, a relative path should be used instead.)";
|
||||
}
|
||||
uses nw:node-ref;
|
||||
}
|
||||
|
||||
augment "/nw:networks/nw:network" {
|
||||
description
|
||||
"Add links to the network data model.";
|
||||
list link {
|
||||
key "link-id";
|
||||
description
|
||||
"A network link connects a local (source) node and
|
||||
a remote (destination) node via a set of the respective
|
||||
node's termination points. It is possible to have several
|
||||
links between the same source and destination nodes.
|
||||
Likewise, a link could potentially be re-homed between
|
||||
termination points. Therefore, in order to ensure that we
|
||||
would always know to distinguish between links, every link
|
||||
is identified by a dedicated link identifier. Note that a
|
||||
link models a point-to-point link, not a multipoint link.";
|
||||
leaf link-id {
|
||||
type link-id;
|
||||
description
|
||||
"The identifier of a link in the topology.
|
||||
A link is specific to a topology to which it belongs.";
|
||||
}
|
||||
container source {
|
||||
description
|
||||
"This container holds the logical source of a particular
|
||||
link.";
|
||||
leaf source-node {
|
||||
type leafref {
|
||||
path "../../../nw:node/nw:node-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"Source node identifier. Must be in the same topology.";
|
||||
}
|
||||
leaf source-tp {
|
||||
type leafref {
|
||||
path "../../../nw:node[nw:node-id=current()/../"+
|
||||
"source-node]/termination-point/tp-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"This termination point is located within the source node
|
||||
and terminates the link.";
|
||||
}
|
||||
}
|
||||
|
||||
container destination {
|
||||
description
|
||||
"This container holds the logical destination of a
|
||||
particular link.";
|
||||
leaf dest-node {
|
||||
type leafref {
|
||||
path "../../../nw:node/nw:node-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"Destination node identifier. Must be in the same
|
||||
network.";
|
||||
}
|
||||
leaf dest-tp {
|
||||
type leafref {
|
||||
path "../../../nw:node[nw:node-id=current()/../"+
|
||||
"dest-node]/termination-point/tp-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"This termination point is located within the
|
||||
destination node and terminates the link.";
|
||||
}
|
||||
}
|
||||
list supporting-link {
|
||||
key "network-ref link-ref";
|
||||
description
|
||||
"Identifies the link or links on which this link depends.";
|
||||
leaf network-ref {
|
||||
type leafref {
|
||||
path "../../../nw:supporting-network/nw:network-ref";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"This leaf identifies in which underlay topology
|
||||
the supporting link is present.";
|
||||
}
|
||||
|
||||
leaf link-ref {
|
||||
type leafref {
|
||||
path "/nw:networks/nw:network[nw:network-id=current()/"+
|
||||
"../network-ref]/link/link-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"This leaf identifies a link that is a part
|
||||
of this link's underlay. Reference loops in which
|
||||
a link identifies itself as its underlay, either
|
||||
directly or transitively, are not allowed.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
augment "/nw:networks/nw:network/nw:node" {
|
||||
description
|
||||
"Augments termination points that terminate links.
|
||||
Termination points can ultimately be mapped to interfaces.";
|
||||
list termination-point {
|
||||
key "tp-id";
|
||||
description
|
||||
"A termination point can terminate a link.
|
||||
Depending on the type of topology, a termination point
|
||||
could, for example, refer to a port or an interface.";
|
||||
leaf tp-id {
|
||||
type tp-id;
|
||||
description
|
||||
"Termination point identifier.";
|
||||
}
|
||||
list supporting-termination-point {
|
||||
key "network-ref node-ref tp-ref";
|
||||
description
|
||||
"This list identifies any termination points on which a
|
||||
given termination point depends or onto which it maps.
|
||||
Those termination points will themselves be contained
|
||||
in a supporting node. This dependency information can be
|
||||
inferred from the dependencies between links. Therefore,
|
||||
this item is not separately configurable. Hence, no
|
||||
corresponding constraint needs to be articulated.
|
||||
The corresponding information is simply provided by the
|
||||
implementing system.";
|
||||
|
||||
leaf network-ref {
|
||||
type leafref {
|
||||
path "../../../nw:supporting-node/nw:network-ref";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"This leaf identifies in which topology the
|
||||
supporting termination point is present.";
|
||||
}
|
||||
leaf node-ref {
|
||||
type leafref {
|
||||
path "../../../nw:supporting-node/nw:node-ref";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"This leaf identifies in which node the supporting
|
||||
termination point is present.";
|
||||
}
|
||||
leaf tp-ref {
|
||||
type leafref {
|
||||
path "/nw:networks/nw:network[nw:network-id=current()/"+
|
||||
"../network-ref]/nw:node[nw:node-id=current()/../"+
|
||||
"node-ref]/termination-point/tp-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"Reference to the underlay node (the underlay node must
|
||||
be in a different topology).";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
192
gnpy/yang/ext/ietf-network@2018-02-26.yang
Normal file
192
gnpy/yang/ext/ietf-network@2018-02-26.yang
Normal file
@@ -0,0 +1,192 @@
|
||||
module ietf-network {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-network";
|
||||
prefix nw;
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF I2RS (Interface to the Routing System) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/i2rs/>
|
||||
WG List: <mailto:i2rs@ietf.org>
|
||||
|
||||
Editor: Alexander Clemm
|
||||
<mailto:ludwig@clemm.org>
|
||||
|
||||
Editor: Jan Medved
|
||||
<mailto:jmedved@cisco.com>
|
||||
|
||||
Editor: Robert Varga
|
||||
<mailto:robert.varga@pantheon.tech>
|
||||
|
||||
Editor: Nitin Bahadur
|
||||
<mailto:nitin_bahadur@yahoo.com>
|
||||
|
||||
Editor: Hariharan Ananthakrishnan
|
||||
<mailto:hari@packetdesign.com>
|
||||
|
||||
Editor: Xufeng Liu
|
||||
<mailto:xufeng.liu.ietf@gmail.com>";
|
||||
description
|
||||
"This module defines a common base data model for a collection
|
||||
of nodes in a network. Node definitions are further used
|
||||
in network topologies and inventories.
|
||||
|
||||
Copyright (c) 2018 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8345;
|
||||
see the RFC itself for full legal notices.";
|
||||
|
||||
revision 2018-02-26 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 8345: A YANG Data Model for Network Topologies";
|
||||
}
|
||||
|
||||
typedef node-id {
|
||||
type inet:uri;
|
||||
description
|
||||
"Identifier for a node. The precise structure of the node-id
|
||||
will be up to the implementation. For example, some
|
||||
implementations MAY pick a URI that includes the network-id
|
||||
as part of the path. The identifier SHOULD be chosen
|
||||
such that the same node in a real network topology will
|
||||
always be identified through the same identifier, even if
|
||||
the data model is instantiated in separate datastores. An
|
||||
implementation MAY choose to capture semantics in the
|
||||
identifier -- for example, to indicate the type of node.";
|
||||
}
|
||||
|
||||
typedef network-id {
|
||||
type inet:uri;
|
||||
description
|
||||
"Identifier for a network. The precise structure of the
|
||||
network-id will be up to the implementation. The identifier
|
||||
SHOULD be chosen such that the same network will always be
|
||||
identified through the same identifier, even if the data model
|
||||
is instantiated in separate datastores. An implementation MAY
|
||||
choose to capture semantics in the identifier -- for example,
|
||||
to indicate the type of network.";
|
||||
}
|
||||
|
||||
grouping network-ref {
|
||||
description
|
||||
"Contains the information necessary to reference a network --
|
||||
for example, an underlay network.";
|
||||
leaf network-ref {
|
||||
type leafref {
|
||||
path "/nw:networks/nw:network/nw:network-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"Used to reference a network -- for example, an underlay
|
||||
network.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping node-ref {
|
||||
description
|
||||
"Contains the information necessary to reference a node.";
|
||||
leaf node-ref {
|
||||
type leafref {
|
||||
path "/nw:networks/nw:network[nw:network-id=current()/../"+
|
||||
"network-ref]/nw:node/nw:node-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"Used to reference a node.
|
||||
Nodes are identified relative to the network that
|
||||
contains them.";
|
||||
}
|
||||
uses network-ref;
|
||||
}
|
||||
|
||||
container networks {
|
||||
description
|
||||
"Serves as a top-level container for a list of networks.";
|
||||
list network {
|
||||
key "network-id";
|
||||
description
|
||||
"Describes a network.
|
||||
A network typically contains an inventory of nodes,
|
||||
topological information (augmented through the
|
||||
network-topology data model), and layering information.";
|
||||
leaf network-id {
|
||||
type network-id;
|
||||
description
|
||||
"Identifies a network.";
|
||||
}
|
||||
container network-types {
|
||||
description
|
||||
"Serves as an augmentation target.
|
||||
The network type is indicated through corresponding
|
||||
presence containers augmented into this container.";
|
||||
}
|
||||
list supporting-network {
|
||||
key "network-ref";
|
||||
description
|
||||
"An underlay network, used to represent layered network
|
||||
topologies.";
|
||||
leaf network-ref {
|
||||
type leafref {
|
||||
path "/nw:networks/nw:network/nw:network-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"References the underlay network.";
|
||||
}
|
||||
}
|
||||
|
||||
list node {
|
||||
key "node-id";
|
||||
description
|
||||
"The inventory of nodes of this network.";
|
||||
leaf node-id {
|
||||
type node-id;
|
||||
description
|
||||
"Uniquely identifies a node within the containing
|
||||
network.";
|
||||
}
|
||||
list supporting-node {
|
||||
key "network-ref node-ref";
|
||||
description
|
||||
"Represents another node that is in an underlay network
|
||||
and that supports this node. Used to represent layering
|
||||
structure.";
|
||||
leaf network-ref {
|
||||
type leafref {
|
||||
path "../../../nw:supporting-network/nw:network-ref";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"References the underlay network of which the
|
||||
underlay node is a part.";
|
||||
}
|
||||
leaf node-ref {
|
||||
type leafref {
|
||||
path "/nw:networks/nw:network/nw:node/nw:node-id";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"References the underlay node itself.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1776
gnpy/yang/ext/ietf-optical-impairment-topology@2024-05-21.yang
Normal file
1776
gnpy/yang/ext/ietf-optical-impairment-topology@2024-05-21.yang
Normal file
File diff suppressed because it is too large
Load Diff
771
gnpy/yang/ext/ietf-routing-types@2017-12-04.yang
Normal file
771
gnpy/yang/ext/ietf-routing-types@2017-12-04.yang
Normal file
@@ -0,0 +1,771 @@
|
||||
module ietf-routing-types {
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-routing-types";
|
||||
prefix rt-types;
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF RTGWG - Routing Area Working Group";
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/rtgwg/>
|
||||
WG List: <mailto:rtgwg@ietf.org>
|
||||
|
||||
Editors: Xufeng Liu
|
||||
<mailto:Xufeng_Liu@jabail.com>
|
||||
Yingzhen Qu
|
||||
<mailto:yingzhen.qu@huawei.com>
|
||||
Acee Lindem
|
||||
<mailto:acee@cisco.com>
|
||||
Christian Hopps
|
||||
<mailto:chopps@chopps.org>
|
||||
Lou Berger
|
||||
<mailto:lberger@labn.com>";
|
||||
|
||||
description
|
||||
"This module contains a collection of YANG data types
|
||||
considered generally useful for routing protocols.
|
||||
|
||||
Copyright (c) 2017 IETF Trust and the persons
|
||||
identified as authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8294; see
|
||||
the RFC itself for full legal notices.";
|
||||
revision 2017-12-04 {
|
||||
description "Initial revision.";
|
||||
reference
|
||||
"RFC 8294: Common YANG Data Types for the Routing Area.
|
||||
Section 3.";
|
||||
}
|
||||
|
||||
/*** Identities related to MPLS/GMPLS ***/
|
||||
|
||||
identity mpls-label-special-purpose-value {
|
||||
description
|
||||
"Base identity for deriving identities describing
|
||||
special-purpose Multiprotocol Label Switching (MPLS) label
|
||||
values.";
|
||||
reference
|
||||
"RFC 7274: Allocating and Retiring Special-Purpose MPLS
|
||||
Labels.";
|
||||
}
|
||||
|
||||
identity ipv4-explicit-null-label {
|
||||
base mpls-label-special-purpose-value;
|
||||
description
|
||||
"This identity represents the IPv4 Explicit NULL Label.";
|
||||
reference
|
||||
"RFC 3032: MPLS Label Stack Encoding. Section 2.1.";
|
||||
}
|
||||
|
||||
identity router-alert-label {
|
||||
base mpls-label-special-purpose-value;
|
||||
description
|
||||
"This identity represents the Router Alert Label.";
|
||||
reference
|
||||
"RFC 3032: MPLS Label Stack Encoding. Section 2.1.";
|
||||
}
|
||||
|
||||
identity ipv6-explicit-null-label {
|
||||
base mpls-label-special-purpose-value;
|
||||
description
|
||||
"This identity represents the IPv6 Explicit NULL Label.";
|
||||
reference
|
||||
"RFC 3032: MPLS Label Stack Encoding. Section 2.1.";
|
||||
}
|
||||
|
||||
identity implicit-null-label {
|
||||
base mpls-label-special-purpose-value;
|
||||
description
|
||||
"This identity represents the Implicit NULL Label.";
|
||||
reference
|
||||
"RFC 3032: MPLS Label Stack Encoding. Section 2.1.";
|
||||
}
|
||||
|
||||
identity entropy-label-indicator {
|
||||
base mpls-label-special-purpose-value;
|
||||
description
|
||||
"This identity represents the Entropy Label Indicator.";
|
||||
reference
|
||||
"RFC 6790: The Use of Entropy Labels in MPLS Forwarding.
|
||||
Sections 3 and 10.1.";
|
||||
}
|
||||
|
||||
identity gal-label {
|
||||
base mpls-label-special-purpose-value;
|
||||
description
|
||||
"This identity represents the Generic Associated Channel
|
||||
(G-ACh) Label (GAL).";
|
||||
reference
|
||||
"RFC 5586: MPLS Generic Associated Channel.
|
||||
Sections 4 and 10.";
|
||||
}
|
||||
|
||||
identity oam-alert-label {
|
||||
base mpls-label-special-purpose-value;
|
||||
description
|
||||
"This identity represents the OAM Alert Label.";
|
||||
reference
|
||||
"RFC 3429: Assignment of the 'OAM Alert Label' for
|
||||
Multiprotocol Label Switching Architecture (MPLS)
|
||||
Operation and Maintenance (OAM) Functions.
|
||||
Sections 3 and 6.";
|
||||
}
|
||||
|
||||
identity extension-label {
|
||||
base mpls-label-special-purpose-value;
|
||||
description
|
||||
"This identity represents the Extension Label.";
|
||||
reference
|
||||
"RFC 7274: Allocating and Retiring Special-Purpose MPLS
|
||||
Labels. Sections 3.1 and 5.";
|
||||
}
|
||||
|
||||
/*** Collection of types related to routing ***/
|
||||
|
||||
typedef router-id {
|
||||
type yang:dotted-quad;
|
||||
description
|
||||
"A 32-bit number in the dotted-quad format assigned to each
|
||||
router. This number uniquely identifies the router within
|
||||
an Autonomous System.";
|
||||
}
|
||||
|
||||
/*** Collection of types related to VPNs ***/
|
||||
|
||||
typedef route-target {
|
||||
type string {
|
||||
pattern
|
||||
'(0:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
|
||||
+ '42949672[0-8][0-9]|'
|
||||
+ '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
|
||||
+ '42949[0-5][0-9]{4}|'
|
||||
+ '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
|
||||
+ '42[0-8][0-9]{7}|4[01][0-9]{8}|'
|
||||
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))|'
|
||||
+ '(1:((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
|
||||
+ '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
|
||||
+ '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
|
||||
+ '655[0-2][0-9]|'
|
||||
+ '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
|
||||
+ '(2:(429496729[0-5]|42949672[0-8][0-9]|'
|
||||
+ '4294967[01][0-9]{2}|'
|
||||
+ '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
|
||||
+ '4294[0-8][0-9]{5}|'
|
||||
+ '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
|
||||
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
|
||||
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
|
||||
+ '(6(:[a-fA-F0-9]{2}){6})|'
|
||||
+ '(([3-57-9a-fA-F]|[1-9a-fA-F][0-9a-fA-F]{1,3}):'
|
||||
+ '[0-9a-fA-F]{1,12})';
|
||||
}
|
||||
|
||||
description
|
||||
"A Route Target is an 8-octet BGP extended community
|
||||
initially identifying a set of sites in a BGP VPN
|
||||
(RFC 4364). However, it has since taken on a more general
|
||||
role in BGP route filtering. A Route Target consists of two
|
||||
or three fields: a 2-octet Type field, an administrator
|
||||
field, and, optionally, an assigned number field.
|
||||
|
||||
According to the data formats for types 0, 1, 2, and 6 as
|
||||
defined in RFC 4360, RFC 5668, and RFC 7432, the encoding
|
||||
pattern is defined as:
|
||||
|
||||
0:2-octet-asn:4-octet-number
|
||||
1:4-octet-ipv4addr:2-octet-number
|
||||
2:4-octet-asn:2-octet-number
|
||||
6:6-octet-mac-address
|
||||
|
||||
Additionally, a generic pattern is defined for future
|
||||
Route Target types:
|
||||
|
||||
2-octet-other-hex-number:6-octet-hex-number
|
||||
|
||||
Some valid examples are 0:100:100, 1:1.1.1.1:100,
|
||||
2:1234567890:203, and 6:26:00:08:92:78:00.";
|
||||
reference
|
||||
"RFC 4360: BGP Extended Communities Attribute.
|
||||
RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
|
||||
RFC 5668: 4-Octet AS Specific BGP Extended Community.
|
||||
RFC 7432: BGP MPLS-Based Ethernet VPN.";
|
||||
}
|
||||
|
||||
typedef ipv6-route-target {
|
||||
type string {
|
||||
pattern
|
||||
'((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
|
||||
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
|
||||
+ '(((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}'
|
||||
+ '(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])))'
|
||||
+ ':'
|
||||
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)';
|
||||
pattern '((([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
|
||||
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))'
|
||||
+ ':'
|
||||
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)';
|
||||
}
|
||||
description
|
||||
"An IPv6 Route Target is a 20-octet BGP IPv6 Address
|
||||
Specific Extended Community serving the same function
|
||||
as a standard 8-octet Route Target, except that it only
|
||||
allows an IPv6 address as the global administrator.
|
||||
The format is <ipv6-address:2-octet-number>.
|
||||
|
||||
Two valid examples are 2001:db8::1:6544 and
|
||||
2001:db8::5eb1:791:6b37:17958.";
|
||||
reference
|
||||
"RFC 5701: IPv6 Address Specific BGP Extended Community
|
||||
Attribute.";
|
||||
}
|
||||
|
||||
typedef route-target-type {
|
||||
type enumeration {
|
||||
enum import {
|
||||
value 0;
|
||||
description
|
||||
"The Route Target applies to route import.";
|
||||
}
|
||||
enum export {
|
||||
value 1;
|
||||
description
|
||||
"The Route Target applies to route export.";
|
||||
}
|
||||
|
||||
enum both {
|
||||
value 2;
|
||||
description
|
||||
"The Route Target applies to both route import and
|
||||
route export.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Indicates the role a Route Target takes in route filtering.";
|
||||
reference
|
||||
"RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).";
|
||||
}
|
||||
|
||||
typedef route-distinguisher {
|
||||
type string {
|
||||
pattern
|
||||
'(0:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
|
||||
+ '42949672[0-8][0-9]|'
|
||||
+ '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
|
||||
+ '42949[0-5][0-9]{4}|'
|
||||
+ '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
|
||||
+ '42[0-8][0-9]{7}|4[01][0-9]{8}|'
|
||||
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))|'
|
||||
+ '(1:((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
|
||||
+ '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
|
||||
+ '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
|
||||
+ '655[0-2][0-9]|'
|
||||
+ '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
|
||||
+ '(2:(429496729[0-5]|42949672[0-8][0-9]|'
|
||||
+ '4294967[01][0-9]{2}|'
|
||||
+ '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
|
||||
+ '4294[0-8][0-9]{5}|'
|
||||
+ '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
|
||||
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
|
||||
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
|
||||
+ '(6(:[a-fA-F0-9]{2}){6})|'
|
||||
+ '(([3-57-9a-fA-F]|[1-9a-fA-F][0-9a-fA-F]{1,3}):'
|
||||
+ '[0-9a-fA-F]{1,12})';
|
||||
}
|
||||
|
||||
description
|
||||
"A Route Distinguisher is an 8-octet value used to
|
||||
distinguish routes from different BGP VPNs (RFC 4364).
|
||||
A Route Distinguisher will have the same format as a
|
||||
Route Target as per RFC 4360 and will consist of
|
||||
two or three fields: a 2-octet Type field, an administrator
|
||||
field, and, optionally, an assigned number field.
|
||||
|
||||
According to the data formats for types 0, 1, 2, and 6 as
|
||||
defined in RFC 4360, RFC 5668, and RFC 7432, the encoding
|
||||
pattern is defined as:
|
||||
|
||||
0:2-octet-asn:4-octet-number
|
||||
1:4-octet-ipv4addr:2-octet-number
|
||||
2:4-octet-asn:2-octet-number
|
||||
6:6-octet-mac-address
|
||||
|
||||
Additionally, a generic pattern is defined for future
|
||||
route discriminator types:
|
||||
|
||||
2-octet-other-hex-number:6-octet-hex-number
|
||||
|
||||
Some valid examples are 0:100:100, 1:1.1.1.1:100,
|
||||
2:1234567890:203, and 6:26:00:08:92:78:00.";
|
||||
reference
|
||||
"RFC 4360: BGP Extended Communities Attribute.
|
||||
RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
|
||||
RFC 5668: 4-Octet AS Specific BGP Extended Community.
|
||||
RFC 7432: BGP MPLS-Based Ethernet VPN.";
|
||||
}
|
||||
|
||||
typedef route-origin {
|
||||
type string {
|
||||
pattern
|
||||
'(0:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
|
||||
+ '42949672[0-8][0-9]|'
|
||||
+ '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
|
||||
+ '42949[0-5][0-9]{4}|'
|
||||
+ '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
|
||||
+ '42[0-8][0-9]{7}|4[01][0-9]{8}|'
|
||||
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))|'
|
||||
+ '(1:((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
|
||||
+ '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
|
||||
+ '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
|
||||
+ '655[0-2][0-9]|'
|
||||
+ '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
|
||||
+ '(2:(429496729[0-5]|42949672[0-8][0-9]|'
|
||||
+ '4294967[01][0-9]{2}|'
|
||||
+ '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
|
||||
+ '4294[0-8][0-9]{5}|'
|
||||
+ '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
|
||||
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
|
||||
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
|
||||
+ '(6(:[a-fA-F0-9]{2}){6})|'
|
||||
+ '(([3-57-9a-fA-F]|[1-9a-fA-F][0-9a-fA-F]{1,3}):'
|
||||
+ '[0-9a-fA-F]{1,12})';
|
||||
}
|
||||
description
|
||||
"A Route Origin is an 8-octet BGP extended community
|
||||
identifying the set of sites where the BGP route
|
||||
originated (RFC 4364). A Route Origin will have the same
|
||||
format as a Route Target as per RFC 4360 and will consist
|
||||
of two or three fields: a 2-octet Type field, an
|
||||
administrator field, and, optionally, an assigned number
|
||||
field.
|
||||
|
||||
According to the data formats for types 0, 1, 2, and 6 as
|
||||
defined in RFC 4360, RFC 5668, and RFC 7432, the encoding
|
||||
pattern is defined as:
|
||||
|
||||
0:2-octet-asn:4-octet-number
|
||||
1:4-octet-ipv4addr:2-octet-number
|
||||
2:4-octet-asn:2-octet-number
|
||||
6:6-octet-mac-address
|
||||
Additionally, a generic pattern is defined for future
|
||||
Route Origin types:
|
||||
|
||||
2-octet-other-hex-number:6-octet-hex-number
|
||||
|
||||
Some valid examples are 0:100:100, 1:1.1.1.1:100,
|
||||
2:1234567890:203, and 6:26:00:08:92:78:00.";
|
||||
reference
|
||||
"RFC 4360: BGP Extended Communities Attribute.
|
||||
RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
|
||||
RFC 5668: 4-Octet AS Specific BGP Extended Community.
|
||||
RFC 7432: BGP MPLS-Based Ethernet VPN.";
|
||||
}
|
||||
|
||||
typedef ipv6-route-origin {
|
||||
type string {
|
||||
pattern
|
||||
'((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
|
||||
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
|
||||
+ '(((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}'
|
||||
+ '(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])))'
|
||||
+ ':'
|
||||
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)';
|
||||
pattern '((([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
|
||||
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))'
|
||||
+ ':'
|
||||
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
|
||||
+ '6[0-4][0-9]{3}|'
|
||||
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)';
|
||||
}
|
||||
description
|
||||
"An IPv6 Route Origin is a 20-octet BGP IPv6 Address
|
||||
Specific Extended Community serving the same function
|
||||
as a standard 8-octet route, except that it only allows
|
||||
an IPv6 address as the global administrator. The format
|
||||
is <ipv6-address:2-octet-number>.
|
||||
|
||||
Two valid examples are 2001:db8::1:6544 and
|
||||
2001:db8::5eb1:791:6b37:17958.";
|
||||
reference
|
||||
"RFC 5701: IPv6 Address Specific BGP Extended Community
|
||||
Attribute.";
|
||||
}
|
||||
|
||||
/*** Collection of types common to multicast ***/
|
||||
|
||||
typedef ipv4-multicast-group-address {
|
||||
type inet:ipv4-address {
|
||||
pattern '(2((2[4-9])|(3[0-9]))\.).*';
|
||||
}
|
||||
description
|
||||
"This type represents an IPv4 multicast group address,
|
||||
which is in the range of 224.0.0.0 to 239.255.255.255.";
|
||||
reference
|
||||
"RFC 1112: Host Extensions for IP Multicasting.";
|
||||
}
|
||||
|
||||
typedef ipv6-multicast-group-address {
|
||||
type inet:ipv6-address {
|
||||
pattern '(([fF]{2}[0-9a-fA-F]{2}):).*';
|
||||
}
|
||||
description
|
||||
"This type represents an IPv6 multicast group address,
|
||||
which is in the range of ff00::/8.";
|
||||
reference
|
||||
"RFC 4291: IP Version 6 Addressing Architecture. Section 2.7.
|
||||
RFC 7346: IPv6 Multicast Address Scopes.";
|
||||
}
|
||||
|
||||
typedef ip-multicast-group-address {
|
||||
type union {
|
||||
type ipv4-multicast-group-address;
|
||||
type ipv6-multicast-group-address;
|
||||
}
|
||||
description
|
||||
"This type represents a version-neutral IP multicast group
|
||||
address. The format of the textual representation implies
|
||||
the IP version.";
|
||||
}
|
||||
|
||||
typedef ipv4-multicast-source-address {
|
||||
type union {
|
||||
type enumeration {
|
||||
enum * {
|
||||
description
|
||||
"Any source address.";
|
||||
}
|
||||
}
|
||||
type inet:ipv4-address;
|
||||
}
|
||||
description
|
||||
"Multicast source IPv4 address type.";
|
||||
}
|
||||
|
||||
typedef ipv6-multicast-source-address {
|
||||
type union {
|
||||
type enumeration {
|
||||
enum * {
|
||||
description
|
||||
"Any source address.";
|
||||
}
|
||||
}
|
||||
type inet:ipv6-address;
|
||||
}
|
||||
description
|
||||
"Multicast source IPv6 address type.";
|
||||
}
|
||||
|
||||
/*** Collection of types common to protocols ***/
|
||||
|
||||
typedef bandwidth-ieee-float32 {
|
||||
type string {
|
||||
pattern
|
||||
'0[xX](0((\.0?)?[pP](\+)?0?|(\.0?))|'
|
||||
+ '1(\.([0-9a-fA-F]{0,5}[02468aAcCeE]?)?)?[pP](\+)?(12[0-7]|'
|
||||
+ '1[01][0-9]|0?[0-9]?[0-9])?)';
|
||||
}
|
||||
description
|
||||
"Bandwidth in IEEE 754 floating-point 32-bit binary format:
|
||||
(-1)**(S) * 2**(Exponent-127) * (1 + Fraction),
|
||||
where Exponent uses 8 bits and Fraction uses 23 bits.
|
||||
The units are octets per second.
|
||||
The encoding format is the external hexadecimal-significant
|
||||
character sequences specified in IEEE 754 and ISO/IEC C99.
|
||||
The format is restricted to be normalized, non-negative, and
|
||||
non-fraction: 0x1.hhhhhhp{+}d, 0X1.HHHHHHP{+}D, or 0x0p0,
|
||||
where 'h' and 'H' are hexadecimal digits and 'd' and 'D' are
|
||||
integers in the range of [0..127].
|
||||
When six hexadecimal digits are used for 'hhhhhh' or
|
||||
'HHHHHH', the least significant digit must be an even
|
||||
number. 'x' and 'X' indicate hexadecimal; 'p' and 'P'
|
||||
indicate a power of two. Some examples are 0x0p0, 0x1p10,
|
||||
and 0x1.abcde2p+20.";
|
||||
reference
|
||||
"IEEE Std 754-2008: IEEE Standard for Floating-Point
|
||||
Arithmetic.
|
||||
ISO/IEC C99: Information technology - Programming
|
||||
Languages - C.";
|
||||
}
|
||||
|
||||
typedef link-access-type {
|
||||
type enumeration {
|
||||
enum broadcast {
|
||||
description
|
||||
"Specify broadcast multi-access network.";
|
||||
}
|
||||
enum non-broadcast-multiaccess {
|
||||
description
|
||||
"Specify Non-Broadcast Multi-Access (NBMA) network.";
|
||||
}
|
||||
enum point-to-multipoint {
|
||||
description
|
||||
"Specify point-to-multipoint network.";
|
||||
}
|
||||
enum point-to-point {
|
||||
description
|
||||
"Specify point-to-point network.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Link access type.";
|
||||
}
|
||||
|
||||
typedef timer-multiplier {
|
||||
type uint8;
|
||||
description
|
||||
"The number of timer value intervals that should be
|
||||
interpreted as a failure.";
|
||||
}
|
||||
|
||||
typedef timer-value-seconds16 {
|
||||
type union {
|
||||
type uint16 {
|
||||
range "1..65535";
|
||||
}
|
||||
type enumeration {
|
||||
enum infinity {
|
||||
description
|
||||
"The timer is set to infinity.";
|
||||
}
|
||||
enum not-set {
|
||||
description
|
||||
"The timer is not set.";
|
||||
}
|
||||
}
|
||||
}
|
||||
units "seconds";
|
||||
description
|
||||
"Timer value type, in seconds (16-bit range).";
|
||||
}
|
||||
|
||||
typedef timer-value-seconds32 {
|
||||
type union {
|
||||
type uint32 {
|
||||
range "1..4294967295";
|
||||
}
|
||||
type enumeration {
|
||||
enum infinity {
|
||||
description
|
||||
"The timer is set to infinity.";
|
||||
}
|
||||
enum not-set {
|
||||
description
|
||||
"The timer is not set.";
|
||||
}
|
||||
}
|
||||
}
|
||||
units "seconds";
|
||||
description
|
||||
"Timer value type, in seconds (32-bit range).";
|
||||
}
|
||||
|
||||
typedef timer-value-milliseconds {
|
||||
type union {
|
||||
type uint32 {
|
||||
range "1..4294967295";
|
||||
}
|
||||
type enumeration {
|
||||
enum infinity {
|
||||
description
|
||||
"The timer is set to infinity.";
|
||||
}
|
||||
enum not-set {
|
||||
description
|
||||
"The timer is not set.";
|
||||
}
|
||||
}
|
||||
}
|
||||
units "milliseconds";
|
||||
description
|
||||
"Timer value type, in milliseconds.";
|
||||
}
|
||||
|
||||
typedef percentage {
|
||||
type uint8 {
|
||||
range "0..100";
|
||||
}
|
||||
description
|
||||
"Integer indicating a percentage value.";
|
||||
}
|
||||
|
||||
typedef timeticks64 {
|
||||
type uint64;
|
||||
description
|
||||
"This type is based on the timeticks type defined in
|
||||
RFC 6991, but with 64-bit width. It represents the time,
|
||||
modulo 2^64, in hundredths of a second between two epochs.";
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types.";
|
||||
}
|
||||
|
||||
typedef uint24 {
|
||||
type uint32 {
|
||||
range "0..16777215";
|
||||
}
|
||||
description
|
||||
"24-bit unsigned integer.";
|
||||
}
|
||||
|
||||
/*** Collection of types related to MPLS/GMPLS ***/
|
||||
|
||||
typedef generalized-label {
|
||||
type binary;
|
||||
description
|
||||
"Generalized Label. Nodes sending and receiving the
|
||||
Generalized Label are aware of the link-specific
|
||||
label context and type.";
|
||||
reference
|
||||
"RFC 3471: Generalized Multi-Protocol Label Switching (GMPLS)
|
||||
Signaling Functional Description. Section 3.2.";
|
||||
}
|
||||
|
||||
typedef mpls-label-special-purpose {
|
||||
type identityref {
|
||||
base mpls-label-special-purpose-value;
|
||||
}
|
||||
description
|
||||
"This type represents the special-purpose MPLS label values.";
|
||||
reference
|
||||
"RFC 3032: MPLS Label Stack Encoding.
|
||||
RFC 7274: Allocating and Retiring Special-Purpose MPLS
|
||||
Labels.";
|
||||
}
|
||||
|
||||
typedef mpls-label-general-use {
|
||||
type uint32 {
|
||||
range "16..1048575";
|
||||
}
|
||||
description
|
||||
"The 20-bit label value in an MPLS label stack as specified
|
||||
in RFC 3032. This label value does not include the
|
||||
encodings of Traffic Class and TTL (Time to Live).
|
||||
The label range specified by this type is for general use,
|
||||
with special-purpose MPLS label values excluded.";
|
||||
reference
|
||||
"RFC 3032: MPLS Label Stack Encoding.";
|
||||
}
|
||||
|
||||
typedef mpls-label {
|
||||
type union {
|
||||
type mpls-label-special-purpose;
|
||||
type mpls-label-general-use;
|
||||
}
|
||||
description
|
||||
"The 20-bit label value in an MPLS label stack as specified
|
||||
in RFC 3032. This label value does not include the
|
||||
encodings of Traffic Class and TTL.";
|
||||
reference
|
||||
"RFC 3032: MPLS Label Stack Encoding.";
|
||||
}
|
||||
|
||||
/*** Groupings **/
|
||||
|
||||
grouping mpls-label-stack {
|
||||
description
|
||||
"This grouping specifies an MPLS label stack. The label
|
||||
stack is encoded as a list of label stack entries. The
|
||||
list key is an identifier that indicates the relative
|
||||
ordering of each entry, with the lowest-value identifier
|
||||
corresponding to the top of the label stack.";
|
||||
container mpls-label-stack {
|
||||
description
|
||||
"Container for a list of MPLS label stack entries.";
|
||||
list entry {
|
||||
key "id";
|
||||
description
|
||||
"List of MPLS label stack entries.";
|
||||
leaf id {
|
||||
type uint8;
|
||||
description
|
||||
"Identifies the entry in a sequence of MPLS label
|
||||
stack entries. An entry with a smaller identifier
|
||||
value precedes an entry with a larger identifier
|
||||
value in the label stack. The value of this ID has
|
||||
no semantic meaning other than relative ordering
|
||||
and referencing the entry.";
|
||||
}
|
||||
leaf label {
|
||||
type rt-types:mpls-label;
|
||||
description
|
||||
"Label value.";
|
||||
}
|
||||
|
||||
leaf ttl {
|
||||
type uint8;
|
||||
description
|
||||
"Time to Live (TTL).";
|
||||
reference
|
||||
"RFC 3032: MPLS Label Stack Encoding.";
|
||||
}
|
||||
leaf traffic-class {
|
||||
type uint8 {
|
||||
range "0..7";
|
||||
}
|
||||
description
|
||||
"Traffic Class (TC).";
|
||||
reference
|
||||
"RFC 5462: Multiprotocol Label Switching (MPLS) Label
|
||||
Stack Entry: 'EXP' Field Renamed to 'Traffic Class'
|
||||
Field.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping vpn-route-targets {
|
||||
description
|
||||
"A grouping that specifies Route Target import-export rules
|
||||
used in BGP-enabled VPNs.";
|
||||
reference
|
||||
"RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
|
||||
RFC 4664: Framework for Layer 2 Virtual Private Networks
|
||||
(L2VPNs).";
|
||||
list vpn-target {
|
||||
key "route-target";
|
||||
description
|
||||
"List of Route Targets.";
|
||||
leaf route-target {
|
||||
type rt-types:route-target;
|
||||
description
|
||||
"Route Target value.";
|
||||
}
|
||||
leaf route-target-type {
|
||||
type rt-types:route-target-type;
|
||||
mandatory true;
|
||||
description
|
||||
"Import/export type of the Route Target.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1952
gnpy/yang/ext/ietf-te-topology@2020-08-06.yang
Normal file
1952
gnpy/yang/ext/ietf-te-topology@2020-08-06.yang
Normal file
File diff suppressed because it is too large
Load Diff
3458
gnpy/yang/ext/ietf-te-types@2022-10-21.yang
Normal file
3458
gnpy/yang/ext/ietf-te-types@2022-10-21.yang
Normal file
File diff suppressed because it is too large
Load Diff
474
gnpy/yang/ext/ietf-yang-types@2013-07-15.yang
Normal file
474
gnpy/yang/ext/ietf-yang-types@2013-07-15.yang
Normal file
@@ -0,0 +1,474 @@
|
||||
module ietf-yang-types {
|
||||
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
|
||||
prefix "yang";
|
||||
|
||||
organization
|
||||
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <http://tools.ietf.org/wg/netmod/>
|
||||
WG List: <mailto:netmod@ietf.org>
|
||||
|
||||
WG Chair: David Kessens
|
||||
<mailto:david.kessens@nsn.com>
|
||||
|
||||
WG Chair: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>
|
||||
|
||||
Editor: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>";
|
||||
|
||||
description
|
||||
"This module contains a collection of generally useful derived
|
||||
YANG data types.
|
||||
|
||||
Copyright (c) 2013 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 6991; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2013-07-15 {
|
||||
description
|
||||
"This revision adds the following new data types:
|
||||
- yang-identifier
|
||||
- hex-string
|
||||
- uuid
|
||||
- dotted-quad";
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
|
||||
revision 2010-09-24 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 6021: Common YANG Data Types";
|
||||
}
|
||||
|
||||
/*** collection of counter and gauge types ***/
|
||||
|
||||
typedef counter32 {
|
||||
type uint32;
|
||||
description
|
||||
"The counter32 type represents a non-negative integer
|
||||
that monotonically increases until it reaches a
|
||||
maximum value of 2^32-1 (4294967295 decimal), when it
|
||||
wraps around and starts increasing again from zero.
|
||||
|
||||
Counters have no defined 'initial' value, and thus, a
|
||||
single value of a counter has (in general) no information
|
||||
content. Discontinuities in the monotonically increasing
|
||||
value normally occur at re-initialization of the
|
||||
management system, and at other times as specified in the
|
||||
description of a schema node using this type. If such
|
||||
other times can occur, for example, the creation of
|
||||
a schema node of type counter32 at times other than
|
||||
re-initialization, then a corresponding schema node
|
||||
should be defined, with an appropriate type, to indicate
|
||||
the last discontinuity.
|
||||
|
||||
The counter32 type should not be used for configuration
|
||||
schema nodes. A default statement SHOULD NOT be used in
|
||||
combination with the type counter32.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the Counter32 type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef zero-based-counter32 {
|
||||
type yang:counter32;
|
||||
default "0";
|
||||
description
|
||||
"The zero-based-counter32 type represents a counter32
|
||||
that has the defined 'initial' value zero.
|
||||
|
||||
A schema node of this type will be set to zero (0) on creation
|
||||
and will thereafter increase monotonically until it reaches
|
||||
a maximum value of 2^32-1 (4294967295 decimal), when it
|
||||
wraps around and starts increasing again from zero.
|
||||
|
||||
Provided that an application discovers a new schema node
|
||||
of this type within the minimum time to wrap, it can use the
|
||||
'initial' value as a delta. It is important for a management
|
||||
station to be aware of this minimum time and the actual time
|
||||
between polls, and to discard data if the actual time is too
|
||||
long or there is no defined minimum time.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the ZeroBasedCounter32 textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 4502: Remote Network Monitoring Management Information
|
||||
Base Version 2";
|
||||
}
|
||||
|
||||
typedef counter64 {
|
||||
type uint64;
|
||||
description
|
||||
"The counter64 type represents a non-negative integer
|
||||
that monotonically increases until it reaches a
|
||||
maximum value of 2^64-1 (18446744073709551615 decimal),
|
||||
when it wraps around and starts increasing again from zero.
|
||||
|
||||
Counters have no defined 'initial' value, and thus, a
|
||||
single value of a counter has (in general) no information
|
||||
content. Discontinuities in the monotonically increasing
|
||||
value normally occur at re-initialization of the
|
||||
management system, and at other times as specified in the
|
||||
description of a schema node using this type. If such
|
||||
other times can occur, for example, the creation of
|
||||
a schema node of type counter64 at times other than
|
||||
re-initialization, then a corresponding schema node
|
||||
should be defined, with an appropriate type, to indicate
|
||||
the last discontinuity.
|
||||
|
||||
The counter64 type should not be used for configuration
|
||||
schema nodes. A default statement SHOULD NOT be used in
|
||||
combination with the type counter64.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the Counter64 type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef zero-based-counter64 {
|
||||
type yang:counter64;
|
||||
default "0";
|
||||
description
|
||||
"The zero-based-counter64 type represents a counter64 that
|
||||
has the defined 'initial' value zero.
|
||||
|
||||
A schema node of this type will be set to zero (0) on creation
|
||||
and will thereafter increase monotonically until it reaches
|
||||
a maximum value of 2^64-1 (18446744073709551615 decimal),
|
||||
when it wraps around and starts increasing again from zero.
|
||||
|
||||
Provided that an application discovers a new schema node
|
||||
of this type within the minimum time to wrap, it can use the
|
||||
'initial' value as a delta. It is important for a management
|
||||
station to be aware of this minimum time and the actual time
|
||||
between polls, and to discard data if the actual time is too
|
||||
long or there is no defined minimum time.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the ZeroBasedCounter64 textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 2856: Textual Conventions for Additional High Capacity
|
||||
Data Types";
|
||||
}
|
||||
|
||||
typedef gauge32 {
|
||||
type uint32;
|
||||
description
|
||||
"The gauge32 type represents a non-negative integer, which
|
||||
may increase or decrease, but shall never exceed a maximum
|
||||
value, nor fall below a minimum value. The maximum value
|
||||
cannot be greater than 2^32-1 (4294967295 decimal), and
|
||||
the minimum value cannot be smaller than 0. The value of
|
||||
a gauge32 has its maximum value whenever the information
|
||||
being modeled is greater than or equal to its maximum
|
||||
value, and has its minimum value whenever the information
|
||||
being modeled is smaller than or equal to its minimum value.
|
||||
If the information being modeled subsequently decreases
|
||||
below (increases above) the maximum (minimum) value, the
|
||||
gauge32 also decreases (increases).
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the Gauge32 type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef gauge64 {
|
||||
type uint64;
|
||||
description
|
||||
"The gauge64 type represents a non-negative integer, which
|
||||
may increase or decrease, but shall never exceed a maximum
|
||||
value, nor fall below a minimum value. The maximum value
|
||||
cannot be greater than 2^64-1 (18446744073709551615), and
|
||||
the minimum value cannot be smaller than 0. The value of
|
||||
a gauge64 has its maximum value whenever the information
|
||||
being modeled is greater than or equal to its maximum
|
||||
value, and has its minimum value whenever the information
|
||||
being modeled is smaller than or equal to its minimum value.
|
||||
If the information being modeled subsequently decreases
|
||||
below (increases above) the maximum (minimum) value, the
|
||||
gauge64 also decreases (increases).
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the CounterBasedGauge64 SMIv2 textual convention defined
|
||||
in RFC 2856";
|
||||
reference
|
||||
"RFC 2856: Textual Conventions for Additional High Capacity
|
||||
Data Types";
|
||||
}
|
||||
|
||||
/*** collection of identifier-related types ***/
|
||||
|
||||
typedef object-identifier {
|
||||
type string {
|
||||
pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
|
||||
+ '(\.(0|([1-9]\d*)))*';
|
||||
}
|
||||
description
|
||||
"The object-identifier type represents administratively
|
||||
assigned names in a registration-hierarchical-name tree.
|
||||
|
||||
Values of this type are denoted as a sequence of numerical
|
||||
non-negative sub-identifier values. Each sub-identifier
|
||||
value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
|
||||
are separated by single dots and without any intermediate
|
||||
whitespace.
|
||||
|
||||
The ASN.1 standard restricts the value space of the first
|
||||
sub-identifier to 0, 1, or 2. Furthermore, the value space
|
||||
of the second sub-identifier is restricted to the range
|
||||
0 to 39 if the first sub-identifier is 0 or 1. Finally,
|
||||
the ASN.1 standard requires that an object identifier
|
||||
has always at least two sub-identifiers. The pattern
|
||||
captures these restrictions.
|
||||
|
||||
Although the number of sub-identifiers is not limited,
|
||||
module designers should realize that there may be
|
||||
implementations that stick with the SMIv2 limit of 128
|
||||
sub-identifiers.
|
||||
|
||||
This type is a superset of the SMIv2 OBJECT IDENTIFIER type
|
||||
since it is not restricted to 128 sub-identifiers. Hence,
|
||||
this type SHOULD NOT be used to represent the SMIv2 OBJECT
|
||||
IDENTIFIER type; the object-identifier-128 type SHOULD be
|
||||
used instead.";
|
||||
reference
|
||||
"ISO9834-1: Information technology -- Open Systems
|
||||
Interconnection -- Procedures for the operation of OSI
|
||||
Registration Authorities: General procedures and top
|
||||
arcs of the ASN.1 Object Identifier tree";
|
||||
}
|
||||
|
||||
typedef object-identifier-128 {
|
||||
type object-identifier {
|
||||
pattern '\d*(\.\d*){1,127}';
|
||||
}
|
||||
description
|
||||
"This type represents object-identifiers restricted to 128
|
||||
sub-identifiers.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the OBJECT IDENTIFIER type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef yang-identifier {
|
||||
type string {
|
||||
length "1..max";
|
||||
pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
|
||||
pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
|
||||
}
|
||||
description
|
||||
"A YANG identifier string as defined by the 'identifier'
|
||||
rule in Section 12 of RFC 6020. An identifier must
|
||||
start with an alphabetic character or an underscore
|
||||
followed by an arbitrary sequence of alphabetic or
|
||||
numeric characters, underscores, hyphens, or dots.
|
||||
|
||||
A YANG identifier MUST NOT start with any possible
|
||||
combination of the lowercase or uppercase character
|
||||
sequence 'xml'.";
|
||||
reference
|
||||
"RFC 6020: YANG - A Data Modeling Language for the Network
|
||||
Configuration Protocol (NETCONF)";
|
||||
}
|
||||
|
||||
/*** collection of types related to date and time***/
|
||||
|
||||
typedef date-and-time {
|
||||
type string {
|
||||
pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
|
||||
+ '(Z|[\+\-]\d{2}:\d{2})';
|
||||
}
|
||||
description
|
||||
"The date-and-time type is a profile of the ISO 8601
|
||||
standard for representation of dates and times using the
|
||||
Gregorian calendar. The profile is defined by the
|
||||
date-time production in Section 5.6 of RFC 3339.
|
||||
|
||||
The date-and-time type is compatible with the dateTime XML
|
||||
schema type with the following notable exceptions:
|
||||
|
||||
(a) The date-and-time type does not allow negative years.
|
||||
|
||||
(b) The date-and-time time-offset -00:00 indicates an unknown
|
||||
time zone (see RFC 3339) while -00:00 and +00:00 and Z
|
||||
all represent the same time zone in dateTime.
|
||||
|
||||
(c) The canonical format (see below) of data-and-time values
|
||||
differs from the canonical format used by the dateTime XML
|
||||
schema type, which requires all times to be in UTC using
|
||||
the time-offset 'Z'.
|
||||
|
||||
This type is not equivalent to the DateAndTime textual
|
||||
convention of the SMIv2 since RFC 3339 uses a different
|
||||
separator between full-date and full-time and provides
|
||||
higher resolution of time-secfrac.
|
||||
|
||||
The canonical format for date-and-time values with a known time
|
||||
zone uses a numeric time zone offset that is calculated using
|
||||
the device's configured known offset to UTC time. A change of
|
||||
the device's offset to UTC time will cause date-and-time values
|
||||
to change accordingly. Such changes might happen periodically
|
||||
in case a server follows automatically daylight saving time
|
||||
(DST) time zone offset changes. The canonical format for
|
||||
date-and-time values with an unknown time zone (usually
|
||||
referring to the notion of local time) uses the time-offset
|
||||
-00:00.";
|
||||
reference
|
||||
"RFC 3339: Date and Time on the Internet: Timestamps
|
||||
RFC 2579: Textual Conventions for SMIv2
|
||||
XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
|
||||
}
|
||||
|
||||
typedef timeticks {
|
||||
type uint32;
|
||||
description
|
||||
"The timeticks type represents a non-negative integer that
|
||||
represents the time, modulo 2^32 (4294967296 decimal), in
|
||||
hundredths of a second between two epochs. When a schema
|
||||
node is defined that uses this type, the description of
|
||||
the schema node identifies both of the reference epochs.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the TimeTicks type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef timestamp {
|
||||
type yang:timeticks;
|
||||
description
|
||||
"The timestamp type represents the value of an associated
|
||||
timeticks schema node at which a specific occurrence
|
||||
happened. The specific occurrence must be defined in the
|
||||
description of any schema node defined using this type. When
|
||||
the specific occurrence occurred prior to the last time the
|
||||
associated timeticks attribute was zero, then the timestamp
|
||||
value is zero. Note that this requires all timestamp values
|
||||
to be reset to zero when the value of the associated timeticks
|
||||
attribute reaches 497+ days and wraps around to zero.
|
||||
|
||||
The associated timeticks schema node must be specified
|
||||
in the description of any schema node using this type.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the TimeStamp textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 2579: Textual Conventions for SMIv2";
|
||||
}
|
||||
|
||||
/*** collection of generic address types ***/
|
||||
|
||||
typedef phys-address {
|
||||
type string {
|
||||
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
|
||||
}
|
||||
|
||||
description
|
||||
"Represents media- or physical-level addresses represented
|
||||
as a sequence octets, each octet represented by two hexadecimal
|
||||
numbers. Octets are separated by colons. The canonical
|
||||
representation uses lowercase characters.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the PhysAddress textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 2579: Textual Conventions for SMIv2";
|
||||
}
|
||||
|
||||
typedef mac-address {
|
||||
type string {
|
||||
pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
|
||||
}
|
||||
description
|
||||
"The mac-address type represents an IEEE 802 MAC address.
|
||||
The canonical representation uses lowercase characters.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the MacAddress textual convention of the SMIv2.";
|
||||
reference
|
||||
"IEEE 802: IEEE Standard for Local and Metropolitan Area
|
||||
Networks: Overview and Architecture
|
||||
RFC 2579: Textual Conventions for SMIv2";
|
||||
}
|
||||
|
||||
/*** collection of XML-specific types ***/
|
||||
|
||||
typedef xpath1.0 {
|
||||
type string;
|
||||
description
|
||||
"This type represents an XPATH 1.0 expression.
|
||||
|
||||
When a schema node is defined that uses this type, the
|
||||
description of the schema node MUST specify the XPath
|
||||
context in which the XPath expression is evaluated.";
|
||||
reference
|
||||
"XPATH: XML Path Language (XPath) Version 1.0";
|
||||
}
|
||||
|
||||
/*** collection of string types ***/
|
||||
|
||||
typedef hex-string {
|
||||
type string {
|
||||
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
|
||||
}
|
||||
description
|
||||
"A hexadecimal string with octets represented as hex digits
|
||||
separated by colons. The canonical representation uses
|
||||
lowercase characters.";
|
||||
}
|
||||
|
||||
typedef uuid {
|
||||
type string {
|
||||
pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
|
||||
+ '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
|
||||
}
|
||||
description
|
||||
"A Universally Unique IDentifier in the string representation
|
||||
defined in RFC 4122. The canonical representation uses
|
||||
lowercase characters.
|
||||
|
||||
The following is an example of a UUID in string representation:
|
||||
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
|
||||
";
|
||||
reference
|
||||
"RFC 4122: A Universally Unique IDentifier (UUID) URN
|
||||
Namespace";
|
||||
}
|
||||
|
||||
typedef dotted-quad {
|
||||
type string {
|
||||
pattern
|
||||
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
|
||||
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
|
||||
}
|
||||
description
|
||||
"An unsigned 32-bit number expressed in the dotted-quad
|
||||
notation, i.e., four octets written as decimal numbers
|
||||
and separated with the '.' (full stop) character.";
|
||||
}
|
||||
}
|
||||
1867
gnpy/yang/gnpy-api@2025-06-13.tree
Normal file
1867
gnpy/yang/gnpy-api@2025-06-13.tree
Normal file
File diff suppressed because it is too large
Load Diff
47
gnpy/yang/gnpy-api@2025-06-13.yang
Normal file
47
gnpy/yang/gnpy-api@2025-06-13.yang
Normal file
@@ -0,0 +1,47 @@
|
||||
module gnpy-api {
|
||||
yang-version 1.1;
|
||||
namespace "urn:gnpy-api";
|
||||
|
||||
prefix gapi;
|
||||
|
||||
organization
|
||||
"Telecom Infra Project OOPT PSE Working Group";
|
||||
contact
|
||||
"WG Web: <https://github.com/Telecominfraproject/oopt-gnpy>
|
||||
contact: <mailto:esther.lerouzic@orange.com>
|
||||
";
|
||||
description
|
||||
"YANG model for gnpy network input for path computation simulation params- 2025";
|
||||
|
||||
revision 2025-06-13 {
|
||||
description
|
||||
"First yang model for api";
|
||||
reference
|
||||
"YANG model for network input for API path computation with gnpy";
|
||||
}
|
||||
|
||||
container api {
|
||||
description
|
||||
"Top container for the API data.";
|
||||
list extra-configs {
|
||||
key name;
|
||||
description
|
||||
"List of extra configurations for the amplifiers defined in the
|
||||
equipment libraries.";
|
||||
leaf name {
|
||||
type string;
|
||||
description "Unique name used in the equipment library to reference this config.";
|
||||
}
|
||||
}
|
||||
|
||||
list extra-eqpts {
|
||||
key name;
|
||||
description
|
||||
"List of additional libraries, eg for third party pluggables definitions.";
|
||||
leaf name {
|
||||
type string;
|
||||
description "Unique name of the extra library.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
gnpy/yang/gnpy-edfa-config@2025-04-10.tree
Normal file
21
gnpy/yang/gnpy-edfa-config@2025-04-10.tree
Normal file
@@ -0,0 +1,21 @@
|
||||
module: gnpy-edfa-config
|
||||
+--rw edfa-config
|
||||
+--rw f_min decimal64
|
||||
+--rw f_max decimal64
|
||||
+--ro nf_ripple* decimal64
|
||||
+--ro dgt* decimal64
|
||||
+--ro gain_ripple* decimal64
|
||||
+--ro nf_fit_coeff* [coef_order]
|
||||
+--ro coef_order uint8
|
||||
+--ro nf_coef? decimal64
|
||||
|
||||
augment /gapi:api/gapi:extra-configs:
|
||||
+--rw edfa-config
|
||||
+--rw f_min decimal64
|
||||
+--rw f_max decimal64
|
||||
+--ro nf_ripple* decimal64
|
||||
+--ro dgt* decimal64
|
||||
+--ro gain_ripple* decimal64
|
||||
+--ro nf_fit_coeff* [coef_order]
|
||||
+--ro coef_order uint8
|
||||
+--ro nf_coef? decimal64
|
||||
95
gnpy/yang/gnpy-edfa-config@2025-04-10.yang
Normal file
95
gnpy/yang/gnpy-edfa-config@2025-04-10.yang
Normal file
@@ -0,0 +1,95 @@
|
||||
module gnpy-edfa-config {
|
||||
yang-version 1.1;
|
||||
namespace "urn:gnpy-edaf-config";
|
||||
|
||||
prefix edfa-config;
|
||||
|
||||
import gnpy-api {
|
||||
prefix "gapi";
|
||||
revision-date 2025-06-13;
|
||||
}
|
||||
|
||||
import gnpy-eqpt-config {
|
||||
prefix "geqpt";
|
||||
revision-date 2025-05-26;
|
||||
}
|
||||
|
||||
organization
|
||||
"Telecom Infra Project OOPT PSE Working Group";
|
||||
contact
|
||||
"WG Web: <https://github.com/Telecominfraproject/oopt-gnpy>
|
||||
contact: <mailto:esther.lerouzic@orange.com>
|
||||
";
|
||||
description
|
||||
"YANG model for gnpy network input for path computation extra edfa config- 2025";
|
||||
|
||||
revision 2025-04-10 {
|
||||
description
|
||||
"First yang model for extra edfa config option";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
|
||||
grouping edfa-config-grouping {
|
||||
description
|
||||
"Attributes for detailed configuration of EDFA.";
|
||||
leaf f_min {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
mandatory true;
|
||||
description " Minimum and maximum frequency range for the amplifier.
|
||||
Signal must fit entirely within this range (center frequency and spectrum width
|
||||
";
|
||||
}
|
||||
leaf f_max {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
mandatory true;
|
||||
}
|
||||
leaf-list nf_ripple {
|
||||
config false;
|
||||
type decimal64 {
|
||||
fraction-digits 18;
|
||||
}
|
||||
}
|
||||
leaf-list dgt {
|
||||
config false;
|
||||
type decimal64 {
|
||||
fraction-digits 18;
|
||||
}
|
||||
}
|
||||
leaf-list gain_ripple {
|
||||
config false;
|
||||
type decimal64 {
|
||||
fraction-digits 18;
|
||||
}
|
||||
}
|
||||
list nf_fit_coeff {
|
||||
key coef_order;
|
||||
config false;
|
||||
uses geqpt:polynomial-coef;
|
||||
must "./coef_order <= 3";
|
||||
description "3rd order polynomial NF = f(-dg) coeficients list";
|
||||
}
|
||||
}
|
||||
|
||||
grouping edfa-config {
|
||||
container edfa-config {
|
||||
uses edfa-config-grouping;
|
||||
}
|
||||
}
|
||||
|
||||
container edfa-config {
|
||||
uses edfa-config-grouping;
|
||||
}
|
||||
|
||||
augment "/gapi:api/gapi:extra-configs" {
|
||||
description "Add the list of additional configuration of EDFA in the API request.";
|
||||
when "/gapi:api/gapi:extra-configs" ;
|
||||
uses edfa-config;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
602
gnpy/yang/gnpy-eqpt-config@2025-05-26.tree
Normal file
602
gnpy/yang/gnpy-eqpt-config@2025-05-26.tree
Normal file
@@ -0,0 +1,602 @@
|
||||
module: gnpy-eqpt-config
|
||||
+--rw equipment
|
||||
+--rw library-information
|
||||
| +--rw name? string
|
||||
| +--rw content-schema
|
||||
| | +--rw module* module-with-revision-date
|
||||
| +--rw description* string
|
||||
| +--rw contact* string
|
||||
| +--rw organization? string
|
||||
| +--rw revision* [date]
|
||||
| +--rw date string
|
||||
| +--rw description? string
|
||||
+--rw Edfa* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw other_name* string
|
||||
| +--rw f_min? decimal64
|
||||
| +--rw f_max? decimal64
|
||||
| +--rw allowed_for_design? boolean
|
||||
| +--rw gain_flatmax? decimal64
|
||||
| +--rw gain_min? decimal64
|
||||
| +--rw extended_gain_range? decimal64
|
||||
| +--rw p_max? decimal64
|
||||
| +--rw type_def? identityref
|
||||
| +--rw raman? boolean
|
||||
| +--rw out_voa_auto? boolean
|
||||
| +--rw in_voa_auto? boolean
|
||||
| +--rw voa_step? decimal64
|
||||
| +--rw pmd? decimal64
|
||||
| +--rw pdl? decimal64
|
||||
| +--rw (type_of_model)?
|
||||
| +--:(variable_gain)
|
||||
| | +--rw nf_min? decimal64
|
||||
| | +--rw nf_max? decimal64
|
||||
| | +--rw default_config_from_json? string
|
||||
| +--:(fixed_gain)
|
||||
| | +--rw nf0? decimal64
|
||||
| +--:(openroadm)
|
||||
| | +--rw nf_coef* [coef_order]
|
||||
| | +--rw coef_order uint8
|
||||
| | +--rw nf_coef? decimal64
|
||||
| +--:(dual_stage)
|
||||
| | +--rw preamp_variety? union
|
||||
| | +--rw booster_variety? union
|
||||
| +--:(multi_band)
|
||||
| | +--rw amplifiers* string
|
||||
| +--:(advanced_model)
|
||||
| +--rw advanced_config_from_json? string
|
||||
+--rw Fiber* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw dispersion? decimal64
|
||||
| +--rw gamma? decimal64
|
||||
| +--rw pmd_coef? decimal64
|
||||
| +--rw effective_area? decimal64
|
||||
| +--rw loss_coef_lut* [freq]
|
||||
| | +--rw freq decimal64
|
||||
| | +--rw loss_coef_value? decimal64
|
||||
| +--rw (ref_freq_or_wl)?
|
||||
| +--:(frequency)
|
||||
| | +--rw ref_frequency? decimal64
|
||||
| +--:(wavelength)
|
||||
| +--rw ref_wavelength? decimal64
|
||||
+--rw RamanFiber* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw dispersion? decimal64
|
||||
| +--rw gamma? decimal64
|
||||
| +--rw pmd_coef? decimal64
|
||||
| +--rw effective_area? decimal64
|
||||
| +--rw loss_coef_lut* [freq]
|
||||
| | +--rw freq decimal64
|
||||
| | +--rw loss_coef_value? decimal64
|
||||
| +--rw (ref_freq_or_wl)?
|
||||
| | +--:(frequency)
|
||||
| | | +--rw ref_frequency? decimal64
|
||||
| | +--:(wavelength)
|
||||
| | +--rw ref_wavelength? decimal64
|
||||
| +--rw raman_efficiency* [frequency_offset]
|
||||
| +--rw cr? decimal64
|
||||
| +--rw frequency_offset decimal64
|
||||
+--ro Span* []
|
||||
| +--ro power_mode? boolean
|
||||
| +--ro delta_power_range_dict_db
|
||||
| | +--ro min_value? decimal64
|
||||
| | +--ro max_value? decimal64
|
||||
| | +--ro step? decimal64
|
||||
| +--ro max_length? decimal64
|
||||
| +--ro max_loss? decimal64
|
||||
| +--ro max_fiber_lineic_loss_for_raman? decimal64
|
||||
| +--ro target_extended_gain? decimal64
|
||||
| +--ro length_units? string
|
||||
| +--ro padding? decimal64
|
||||
| +--ro EOL? decimal64
|
||||
| +--ro con_in? decimal64
|
||||
| +--ro con_out? decimal64
|
||||
| +--ro span_loss_ref? decimal64
|
||||
| +--ro power_slope? decimal64
|
||||
| +--ro voa_margin? decimal64
|
||||
| +--ro voa_step? decimal64
|
||||
+--rw Roadm* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw (target_type)?
|
||||
| | +--:(constant_power)
|
||||
| | | +--rw target_pch_out_db? decimal64
|
||||
| | +--:(constant_psd)
|
||||
| | | +--rw target_psd_out_mWperGHz? decimal64
|
||||
| | +--:(constant_psw)
|
||||
| | +--rw target_out_mWperSlotWidth? decimal64
|
||||
| +--rw add_drop_osnr? decimal64
|
||||
| +--rw pmd? decimal64
|
||||
| +--rw pdl? decimal64
|
||||
| +--rw restrictions
|
||||
| | +--rw preamp_variety_list* string
|
||||
| | +--rw booster_variety_list* string
|
||||
| +--rw roadm-path-impairments* [roadm-path-impairments-id]
|
||||
| +--rw roadm-path-impairments-id uint32
|
||||
| +--rw (impairment-type)?
|
||||
| +--:(roadm-express-path)
|
||||
| | +--ro roadm-express-path* []
|
||||
| | +--ro frequency-range
|
||||
| | | +--ro lower-frequency union
|
||||
| | | +--ro upper-frequency union
|
||||
| | +--ro roadm-pmd? union
|
||||
| | +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| | +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| | +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-osnr? l0-types:snr-or-null
|
||||
| +--:(roadm-add-path)
|
||||
| | +--ro roadm-add-path* []
|
||||
| | +--ro frequency-range
|
||||
| | | +--ro lower-frequency union
|
||||
| | | +--ro upper-frequency union
|
||||
| | +--ro roadm-pmd? union
|
||||
| | +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| | +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| | +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-pmax? l0-types:power-dbm-or-null
|
||||
| | +--ro roadm-osnr? l0-types:snr-or-null
|
||||
| | +--ro roadm-noise-figure? l0-types:decimal-5-or-null
|
||||
| +--:(roadm-drop-path)
|
||||
| +--ro roadm-drop-path* []
|
||||
| +--ro frequency-range
|
||||
| | +--ro lower-frequency union
|
||||
| | +--ro upper-frequency union
|
||||
| +--ro roadm-pmd? union
|
||||
| +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-minloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-typloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-pmin? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-pmax? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-ptyp? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-osnr? l0-types:snr-or-null
|
||||
| +--ro roadm-noise-figure? l0-types:decimal-5-or-null
|
||||
+--ro SI* []
|
||||
| +--ro f_min? decimal64
|
||||
| +--ro f_max? decimal64
|
||||
| +--ro spacing? decimal64
|
||||
| +--ro power_dbm? decimal64
|
||||
| +--ro power_range_dict_db
|
||||
| | +--ro min_value? decimal64
|
||||
| | +--ro max_value? decimal64
|
||||
| | +--ro step? decimal64
|
||||
| +--ro type_variety? string
|
||||
| +--ro sys_margins? decimal64
|
||||
| +--ro use_si_channel_count_for_design? boolean
|
||||
| +--ro baud_rate? decimal64
|
||||
| +--ro tx_osnr? decimal64
|
||||
| +--ro roll_off? union
|
||||
| +--ro tx_power_dbm? decimal64
|
||||
+--rw Transceiver* [type_variety]
|
||||
+--rw type_variety string
|
||||
+--rw other_name* string
|
||||
+--rw comment? string
|
||||
+--rw frequency
|
||||
| +--rw min? decimal64
|
||||
| +--rw max? decimal64
|
||||
+--rw mode* [format]
|
||||
+--rw format string
|
||||
+--rw other_name* string
|
||||
+--rw OSNR? decimal64
|
||||
+--rw min_spacing? decimal64
|
||||
+--rw bit_rate? decimal64
|
||||
+--rw cost? decimal64
|
||||
+--rw baud_rate? decimal64
|
||||
+--rw tx_osnr? decimal64
|
||||
+--rw roll_off? union
|
||||
+--rw tx_power_dbm? decimal64
|
||||
+--ro penalties* []
|
||||
| +--ro chromatic_dispersion? decimal64
|
||||
| +--ro pmd? decimal64
|
||||
| +--ro pdl? decimal64
|
||||
| +--ro rx-channel-power-value? decimal64
|
||||
| +--ro penalty_value? decimal64
|
||||
+--rw equalization_offset_db? decimal64
|
||||
+--rw tx-channel-power-min? decimal64
|
||||
+--rw tx-channel-power-max? decimal64
|
||||
+--rw rx-channel-power-min? decimal64
|
||||
+--rw rx-channel-power-max? decimal64
|
||||
|
||||
augment /gapi:api:
|
||||
+--rw equipment
|
||||
+--rw library-information
|
||||
| +--rw name? string
|
||||
| +--rw content-schema
|
||||
| | +--rw module* module-with-revision-date
|
||||
| +--rw description* string
|
||||
| +--rw contact* string
|
||||
| +--rw organization? string
|
||||
| +--rw revision* [date]
|
||||
| +--rw date string
|
||||
| +--rw description? string
|
||||
+--rw Edfa* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw other_name* string
|
||||
| +--rw f_min? decimal64
|
||||
| +--rw f_max? decimal64
|
||||
| +--rw allowed_for_design? boolean
|
||||
| +--rw gain_flatmax? decimal64
|
||||
| +--rw gain_min? decimal64
|
||||
| +--rw extended_gain_range? decimal64
|
||||
| +--rw p_max? decimal64
|
||||
| +--rw type_def? identityref
|
||||
| +--rw raman? boolean
|
||||
| +--rw out_voa_auto? boolean
|
||||
| +--rw in_voa_auto? boolean
|
||||
| +--rw voa_step? decimal64
|
||||
| +--rw pmd? decimal64
|
||||
| +--rw pdl? decimal64
|
||||
| +--rw (type_of_model)?
|
||||
| +--:(variable_gain)
|
||||
| | +--rw nf_min? decimal64
|
||||
| | +--rw nf_max? decimal64
|
||||
| | +--rw default_config_from_json? string
|
||||
| +--:(fixed_gain)
|
||||
| | +--rw nf0? decimal64
|
||||
| +--:(openroadm)
|
||||
| | +--rw nf_coef* [coef_order]
|
||||
| | +--rw coef_order uint8
|
||||
| | +--rw nf_coef? decimal64
|
||||
| +--:(dual_stage)
|
||||
| | +--rw preamp_variety? union
|
||||
| | +--rw booster_variety? union
|
||||
| +--:(multi_band)
|
||||
| | +--rw amplifiers* string
|
||||
| +--:(advanced_model)
|
||||
| +--rw advanced_config_from_json? string
|
||||
+--rw Fiber* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw dispersion? decimal64
|
||||
| +--rw gamma? decimal64
|
||||
| +--rw pmd_coef? decimal64
|
||||
| +--rw effective_area? decimal64
|
||||
| +--rw loss_coef_lut* [freq]
|
||||
| | +--rw freq decimal64
|
||||
| | +--rw loss_coef_value? decimal64
|
||||
| +--rw (ref_freq_or_wl)?
|
||||
| +--:(frequency)
|
||||
| | +--rw ref_frequency? decimal64
|
||||
| +--:(wavelength)
|
||||
| +--rw ref_wavelength? decimal64
|
||||
+--rw RamanFiber* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw dispersion? decimal64
|
||||
| +--rw gamma? decimal64
|
||||
| +--rw pmd_coef? decimal64
|
||||
| +--rw effective_area? decimal64
|
||||
| +--rw loss_coef_lut* [freq]
|
||||
| | +--rw freq decimal64
|
||||
| | +--rw loss_coef_value? decimal64
|
||||
| +--rw (ref_freq_or_wl)?
|
||||
| | +--:(frequency)
|
||||
| | | +--rw ref_frequency? decimal64
|
||||
| | +--:(wavelength)
|
||||
| | +--rw ref_wavelength? decimal64
|
||||
| +--rw raman_efficiency* [frequency_offset]
|
||||
| +--rw cr? decimal64
|
||||
| +--rw frequency_offset decimal64
|
||||
+--ro Span* []
|
||||
| +--ro power_mode? boolean
|
||||
| +--ro delta_power_range_dict_db
|
||||
| | +--ro min_value? decimal64
|
||||
| | +--ro max_value? decimal64
|
||||
| | +--ro step? decimal64
|
||||
| +--ro max_length? decimal64
|
||||
| +--ro max_loss? decimal64
|
||||
| +--ro max_fiber_lineic_loss_for_raman? decimal64
|
||||
| +--ro target_extended_gain? decimal64
|
||||
| +--ro length_units? string
|
||||
| +--ro padding? decimal64
|
||||
| +--ro EOL? decimal64
|
||||
| +--ro con_in? decimal64
|
||||
| +--ro con_out? decimal64
|
||||
| +--ro span_loss_ref? decimal64
|
||||
| +--ro power_slope? decimal64
|
||||
| +--ro voa_margin? decimal64
|
||||
| +--ro voa_step? decimal64
|
||||
+--rw Roadm* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw (target_type)?
|
||||
| | +--:(constant_power)
|
||||
| | | +--rw target_pch_out_db? decimal64
|
||||
| | +--:(constant_psd)
|
||||
| | | +--rw target_psd_out_mWperGHz? decimal64
|
||||
| | +--:(constant_psw)
|
||||
| | +--rw target_out_mWperSlotWidth? decimal64
|
||||
| +--rw add_drop_osnr? decimal64
|
||||
| +--rw pmd? decimal64
|
||||
| +--rw pdl? decimal64
|
||||
| +--rw restrictions
|
||||
| | +--rw preamp_variety_list* string
|
||||
| | +--rw booster_variety_list* string
|
||||
| +--rw roadm-path-impairments* [roadm-path-impairments-id]
|
||||
| +--rw roadm-path-impairments-id uint32
|
||||
| +--rw (impairment-type)?
|
||||
| +--:(roadm-express-path)
|
||||
| | +--ro roadm-express-path* []
|
||||
| | +--ro frequency-range
|
||||
| | | +--ro lower-frequency union
|
||||
| | | +--ro upper-frequency union
|
||||
| | +--ro roadm-pmd? union
|
||||
| | +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| | +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| | +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| +--:(roadm-add-path)
|
||||
| | +--ro roadm-add-path* []
|
||||
| | +--ro frequency-range
|
||||
| | | +--ro lower-frequency union
|
||||
| | | +--ro upper-frequency union
|
||||
| | +--ro roadm-pmd? union
|
||||
| | +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| | +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| | +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-pmax? l0-types:power-dbm-or-null
|
||||
| | +--ro roadm-osnr? l0-types:snr-or-null
|
||||
| | +--ro roadm-noise-figure? l0-types:decimal-5-or-null
|
||||
| +--:(roadm-drop-path)
|
||||
| +--ro roadm-drop-path* []
|
||||
| +--ro frequency-range
|
||||
| | +--ro lower-frequency union
|
||||
| | +--ro upper-frequency union
|
||||
| +--ro roadm-pmd? union
|
||||
| +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-minloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-typloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-pmin? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-pmax? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-ptyp? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-osnr? l0-types:snr-or-null
|
||||
| +--ro roadm-noise-figure? l0-types:decimal-5-or-null
|
||||
+--ro SI* []
|
||||
| +--ro f_min? decimal64
|
||||
| +--ro f_max? decimal64
|
||||
| +--ro spacing? decimal64
|
||||
| +--ro power_dbm? decimal64
|
||||
| +--ro power_range_dict_db
|
||||
| | +--ro min_value? decimal64
|
||||
| | +--ro max_value? decimal64
|
||||
| | +--ro step? decimal64
|
||||
| +--ro type_variety? string
|
||||
| +--ro sys_margins? decimal64
|
||||
| +--ro use_si_channel_count_for_design? boolean
|
||||
| +--ro baud_rate? decimal64
|
||||
| +--ro tx_osnr? decimal64
|
||||
| +--ro roll_off? union
|
||||
| +--ro tx_power_dbm? decimal64
|
||||
+--rw Transceiver* [type_variety]
|
||||
+--rw type_variety string
|
||||
+--rw other_name* string
|
||||
+--rw comment? string
|
||||
+--rw frequency
|
||||
| +--rw min? decimal64
|
||||
| +--rw max? decimal64
|
||||
+--rw mode* [format]
|
||||
+--rw format string
|
||||
+--rw other_name* string
|
||||
+--rw OSNR? decimal64
|
||||
+--rw min_spacing? decimal64
|
||||
+--rw bit_rate? decimal64
|
||||
+--rw cost? decimal64
|
||||
+--rw baud_rate? decimal64
|
||||
+--rw tx_osnr? decimal64
|
||||
+--rw roll_off? union
|
||||
+--rw tx_power_dbm? decimal64
|
||||
+--ro penalties* []
|
||||
| +--ro chromatic_dispersion? decimal64
|
||||
| +--ro pmd? decimal64
|
||||
| +--ro pdl? decimal64
|
||||
| +--ro rx-channel-power-value? decimal64
|
||||
| +--ro penalty_value? decimal64
|
||||
+--rw equalization_offset_db? decimal64
|
||||
+--rw tx-channel-power-min? decimal64
|
||||
+--rw tx-channel-power-max? decimal64
|
||||
+--rw rx-channel-power-min? decimal64
|
||||
+--rw rx-channel-power-max? decimal64
|
||||
augment /gapi:api/gapi:extra-eqpts:
|
||||
+--rw equipment
|
||||
+--rw library-information
|
||||
| +--rw name? string
|
||||
| +--rw content-schema
|
||||
| | +--rw module* module-with-revision-date
|
||||
| +--rw description* string
|
||||
| +--rw contact* string
|
||||
| +--rw organization? string
|
||||
| +--rw revision* [date]
|
||||
| +--rw date string
|
||||
| +--rw description? string
|
||||
+--rw Edfa* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw other_name* string
|
||||
| +--rw f_min? decimal64
|
||||
| +--rw f_max? decimal64
|
||||
| +--rw allowed_for_design? boolean
|
||||
| +--rw gain_flatmax? decimal64
|
||||
| +--rw gain_min? decimal64
|
||||
| +--rw extended_gain_range? decimal64
|
||||
| +--rw p_max? decimal64
|
||||
| +--rw type_def? identityref
|
||||
| +--rw raman? boolean
|
||||
| +--rw out_voa_auto? boolean
|
||||
| +--rw in_voa_auto? boolean
|
||||
| +--rw voa_step? decimal64
|
||||
| +--rw pmd? decimal64
|
||||
| +--rw pdl? decimal64
|
||||
| +--rw (type_of_model)?
|
||||
| +--:(variable_gain)
|
||||
| | +--rw nf_min? decimal64
|
||||
| | +--rw nf_max? decimal64
|
||||
| | +--rw default_config_from_json? string
|
||||
| +--:(fixed_gain)
|
||||
| | +--rw nf0? decimal64
|
||||
| +--:(openroadm)
|
||||
| | +--rw nf_coef* [coef_order]
|
||||
| | +--rw coef_order uint8
|
||||
| | +--rw nf_coef? decimal64
|
||||
| +--:(dual_stage)
|
||||
| | +--rw preamp_variety? union
|
||||
| | +--rw booster_variety? union
|
||||
| +--:(multi_band)
|
||||
| | +--rw amplifiers* string
|
||||
| +--:(advanced_model)
|
||||
| +--rw advanced_config_from_json? string
|
||||
+--rw Fiber* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw dispersion? decimal64
|
||||
| +--rw gamma? decimal64
|
||||
| +--rw pmd_coef? decimal64
|
||||
| +--rw effective_area? decimal64
|
||||
| +--rw loss_coef_lut* [freq]
|
||||
| | +--rw freq decimal64
|
||||
| | +--rw loss_coef_value? decimal64
|
||||
| +--rw (ref_freq_or_wl)?
|
||||
| +--:(frequency)
|
||||
| | +--rw ref_frequency? decimal64
|
||||
| +--:(wavelength)
|
||||
| +--rw ref_wavelength? decimal64
|
||||
+--rw RamanFiber* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw dispersion? decimal64
|
||||
| +--rw gamma? decimal64
|
||||
| +--rw pmd_coef? decimal64
|
||||
| +--rw effective_area? decimal64
|
||||
| +--rw loss_coef_lut* [freq]
|
||||
| | +--rw freq decimal64
|
||||
| | +--rw loss_coef_value? decimal64
|
||||
| +--rw (ref_freq_or_wl)?
|
||||
| | +--:(frequency)
|
||||
| | | +--rw ref_frequency? decimal64
|
||||
| | +--:(wavelength)
|
||||
| | +--rw ref_wavelength? decimal64
|
||||
| +--rw raman_efficiency* [frequency_offset]
|
||||
| +--rw cr? decimal64
|
||||
| +--rw frequency_offset decimal64
|
||||
+--ro Span* []
|
||||
| +--ro power_mode? boolean
|
||||
| +--ro delta_power_range_dict_db
|
||||
| | +--ro min_value? decimal64
|
||||
| | +--ro max_value? decimal64
|
||||
| | +--ro step? decimal64
|
||||
| +--ro max_length? decimal64
|
||||
| +--ro max_loss? decimal64
|
||||
| +--ro max_fiber_lineic_loss_for_raman? decimal64
|
||||
| +--ro target_extended_gain? decimal64
|
||||
| +--ro length_units? string
|
||||
| +--ro padding? decimal64
|
||||
| +--ro EOL? decimal64
|
||||
| +--ro con_in? decimal64
|
||||
| +--ro con_out? decimal64
|
||||
| +--ro span_loss_ref? decimal64
|
||||
| +--ro power_slope? decimal64
|
||||
| +--ro voa_margin? decimal64
|
||||
| +--ro voa_step? decimal64
|
||||
+--rw Roadm* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw (target_type)?
|
||||
| | +--:(constant_power)
|
||||
| | | +--rw target_pch_out_db? decimal64
|
||||
| | +--:(constant_psd)
|
||||
| | | +--rw target_psd_out_mWperGHz? decimal64
|
||||
| | +--:(constant_psw)
|
||||
| | +--rw target_out_mWperSlotWidth? decimal64
|
||||
| +--rw add_drop_osnr? decimal64
|
||||
| +--rw pmd? decimal64
|
||||
| +--rw pdl? decimal64
|
||||
| +--rw restrictions
|
||||
| | +--rw preamp_variety_list* string
|
||||
| | +--rw booster_variety_list* string
|
||||
| +--rw roadm-path-impairments* [roadm-path-impairments-id]
|
||||
| +--rw roadm-path-impairments-id uint32
|
||||
| +--rw (impairment-type)?
|
||||
| +--:(roadm-express-path)
|
||||
| | +--ro roadm-express-path* []
|
||||
| | +--ro frequency-range
|
||||
| | | +--ro lower-frequency union
|
||||
| | | +--ro upper-frequency union
|
||||
| | +--ro roadm-pmd? union
|
||||
| | +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| | +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| | +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| +--:(roadm-add-path)
|
||||
| | +--ro roadm-add-path* []
|
||||
| | +--ro frequency-range
|
||||
| | | +--ro lower-frequency union
|
||||
| | | +--ro upper-frequency union
|
||||
| | +--ro roadm-pmd? union
|
||||
| | +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| | +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| | +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| | +--ro roadm-pmax? l0-types:power-dbm-or-null
|
||||
| | +--ro roadm-osnr? l0-types:snr-or-null
|
||||
| | +--ro roadm-noise-figure? l0-types:decimal-5-or-null
|
||||
| +--:(roadm-drop-path)
|
||||
| +--ro roadm-drop-path* []
|
||||
| +--ro frequency-range
|
||||
| | +--ro lower-frequency union
|
||||
| | +--ro upper-frequency union
|
||||
| +--ro roadm-pmd? union
|
||||
| +--ro roadm-cd? l0-types:decimal-5-or-null
|
||||
| +--ro roadm-pdl? l0-types:power-loss-or-null
|
||||
| +--ro roadm-inband-crosstalk? l0-types:decimal-2-or-null
|
||||
| +--ro roadm-maxloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-minloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-typloss? l0-types:power-loss-or-null
|
||||
| +--ro roadm-pmin? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-pmax? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-ptyp? l0-types:power-dbm-or-null
|
||||
| +--ro roadm-osnr? l0-types:snr-or-null
|
||||
| +--ro roadm-noise-figure? l0-types:decimal-5-or-null
|
||||
+--ro SI* []
|
||||
| +--ro f_min? decimal64
|
||||
| +--ro f_max? decimal64
|
||||
| +--ro spacing? decimal64
|
||||
| +--ro power_dbm? decimal64
|
||||
| +--ro power_range_dict_db
|
||||
| | +--ro min_value? decimal64
|
||||
| | +--ro max_value? decimal64
|
||||
| | +--ro step? decimal64
|
||||
| +--ro type_variety? string
|
||||
| +--ro sys_margins? decimal64
|
||||
| +--ro use_si_channel_count_for_design? boolean
|
||||
| +--ro baud_rate? decimal64
|
||||
| +--ro tx_osnr? decimal64
|
||||
| +--ro roll_off? union
|
||||
| +--ro tx_power_dbm? decimal64
|
||||
+--rw Transceiver* [type_variety]
|
||||
+--rw type_variety string
|
||||
+--rw other_name* string
|
||||
+--rw comment? string
|
||||
+--rw frequency
|
||||
| +--rw min? decimal64
|
||||
| +--rw max? decimal64
|
||||
+--rw mode* [format]
|
||||
+--rw format string
|
||||
+--rw other_name* string
|
||||
+--rw OSNR? decimal64
|
||||
+--rw min_spacing? decimal64
|
||||
+--rw bit_rate? decimal64
|
||||
+--rw cost? decimal64
|
||||
+--rw baud_rate? decimal64
|
||||
+--rw tx_osnr? decimal64
|
||||
+--rw roll_off? union
|
||||
+--rw tx_power_dbm? decimal64
|
||||
+--ro penalties* []
|
||||
| +--ro chromatic_dispersion? decimal64
|
||||
| +--ro pmd? decimal64
|
||||
| +--ro pdl? decimal64
|
||||
| +--ro rx-channel-power-value? decimal64
|
||||
| +--ro penalty_value? decimal64
|
||||
+--rw equalization_offset_db? decimal64
|
||||
+--rw tx-channel-power-min? decimal64
|
||||
+--rw tx-channel-power-max? decimal64
|
||||
+--rw rx-channel-power-min? decimal64
|
||||
+--rw rx-channel-power-max? decimal64
|
||||
1347
gnpy/yang/gnpy-eqpt-config@2025-05-26.yang
Normal file
1347
gnpy/yang/gnpy-eqpt-config@2025-05-26.yang
Normal file
File diff suppressed because it is too large
Load Diff
265
gnpy/yang/gnpy-network-topology@2025-03-01.tree
Normal file
265
gnpy/yang/gnpy-network-topology@2025-03-01.tree
Normal file
@@ -0,0 +1,265 @@
|
||||
module: gnpy-network-topology
|
||||
+--rw topology
|
||||
+--rw elements* [uid]
|
||||
| +--rw uid string
|
||||
| +--rw type identityref
|
||||
| +--rw type_variety? string
|
||||
| +--rw metadata
|
||||
| | +--rw location
|
||||
| | +--rw city? union
|
||||
| | +--rw region? union
|
||||
| | +--rw latitude? Coordinate
|
||||
| | +--rw longitude? Coordinate
|
||||
| +--rw operational
|
||||
| | +--rw (ramanfiber)?
|
||||
| | +--:(RamanFiber)
|
||||
| | | +--rw temperature? decimal64
|
||||
| | | +--rw raman_pumps* [frequency]
|
||||
| | | +--rw power? decimal64
|
||||
| | | +--rw frequency decimal64
|
||||
| | | +--rw propagation_direction? identityref
|
||||
| | +--:(Edfa)
|
||||
| | +--rw gain_target? union
|
||||
| | +--rw tilt_target? union
|
||||
| | +--rw out_voa? union
|
||||
| | +--rw in_voa? union
|
||||
| | +--rw delta_p? union
|
||||
| | +--rw f_min? decimal64
|
||||
| | +--rw f_max? decimal64
|
||||
| +--rw (element-type)?
|
||||
| +--:(FiberRoadm)
|
||||
| | +--rw params
|
||||
| | +--rw (fiberroadmfused)?
|
||||
| | +--:(Fiber)
|
||||
| | | +--rw length decimal64
|
||||
| | | +--rw pmd_coef? decimal64
|
||||
| | | +--rw (ref_freq_or_wl)?
|
||||
| | | | +--:(frequency)
|
||||
| | | | | +--rw ref_frequency? decimal64
|
||||
| | | | +--:(wavelength)
|
||||
| | | | +--rw ref_wavelength? decimal64
|
||||
| | | +--rw (dispersion-vector-or-scalar)?
|
||||
| | | | +--:(scalar)
|
||||
| | | | | +--rw dispersion? decimal64
|
||||
| | | | | +--rw dispersion_slope? decimal64
|
||||
| | | | +--:(vector)
|
||||
| | | | +--rw dispersion_per_frequency* [frequency]
|
||||
| | | | +--rw frequency decimal64
|
||||
| | | | +--rw dispersion? decimal64
|
||||
| | | +--rw effective_area? decimal64
|
||||
| | | +--rw gamma? decimal64
|
||||
| | | +--rw raman_coefficient
|
||||
| | | | +--rw reference_frequency? decimal64
|
||||
| | | | +--rw g0_per_frequency* [frequency_offset]
|
||||
| | | | +--rw frequency_offset decimal64
|
||||
| | | | +--rw g0? decimal64
|
||||
| | | +--rw lumped_losses* [position]
|
||||
| | | | +--rw position decimal64
|
||||
| | | | +--rw loss decimal64
|
||||
| | | +--rw (loss_coef-vector-or-scalar)?
|
||||
| | | | +--:(scalar)
|
||||
| | | | | +--rw loss_coef decimal64
|
||||
| | | | +--:(vector)
|
||||
| | | | +--rw loss_coef_per_frequency* [frequency]
|
||||
| | | | +--rw frequency decimal64
|
||||
| | | | +--rw loss_coef_value? decimal64
|
||||
| | | +--rw length_units identityref
|
||||
| | | +--rw att_in? decimal64
|
||||
| | | +--rw con_in? union
|
||||
| | | +--rw con_out? union
|
||||
| | +--:(RoadmTransceiver)
|
||||
| | | +--rw design_bands* [f_min]
|
||||
| | | | +--rw f_min decimal64
|
||||
| | | | +--rw f_max? decimal64
|
||||
| | | | +--rw (parameter-used-for-design)?
|
||||
| | | | +--:(spacing)
|
||||
| | | | | +--rw spacing? decimal64
|
||||
| | | | +--:(number-of-channels)
|
||||
| | | | +--rw number-of-channels? uint16
|
||||
| | | +--rw per_degree_design_bands_targets* [degree_uid]
|
||||
| | | | +--rw degree_uid -> ../../../../elements/uid
|
||||
| | | | +--rw design_bands* [f_min]
|
||||
| | | | +--rw f_min decimal64
|
||||
| | | | +--rw f_max? decimal64
|
||||
| | | | +--rw (parameter-used-for-design)?
|
||||
| | | | +--:(spacing)
|
||||
| | | | | +--rw spacing? decimal64
|
||||
| | | | +--:(number-of-channels)
|
||||
| | | | +--rw number-of-channels? uint16
|
||||
| | | +--rw (roadm)?
|
||||
| | | +--:(roadm)
|
||||
| | | +--rw (target_type)?
|
||||
| | | | +--:(constant_power)
|
||||
| | | | | +--rw target_pch_out_db? decimal64
|
||||
| | | | +--:(constant_psd)
|
||||
| | | | | +--rw target_psd_out_mWperGHz? decimal64
|
||||
| | | | +--:(constant_psw)
|
||||
| | | | +--rw target_out_mWperSlotWidth? decimal64
|
||||
| | | +--rw restrictions
|
||||
| | | | +--rw preamp_variety_list* string
|
||||
| | | | +--rw booster_variety_list* string
|
||||
| | | +--rw per_degree_power_targets* [degree_uid]
|
||||
| | | | +--rw degree_uid -> ../../../../elements/uid
|
||||
| | | | +--rw (per_degree_target_type)?
|
||||
| | | | +--:(constant_power)
|
||||
| | | | | +--rw per_degree_pch_out_db? decimal64
|
||||
| | | | +--:(constant_psd)
|
||||
| | | | | +--rw per_degree_psd_out_mWperGHz? decimal64
|
||||
| | | | +--:(constant_psw)
|
||||
| | | | +--rw per_degree_psd_out_mWperSlotWidth? decimal64
|
||||
| | | +--rw per_degree_impairments* [from_degree to_degree]
|
||||
| | | +--rw from_degree -> ../../../../elements/uid
|
||||
| | | +--rw to_degree -> ../../../../elements/uid
|
||||
| | | +--rw impairment_id? uint32
|
||||
| | +--:(Fused)
|
||||
| | | +--rw loss? union
|
||||
| | +--:(Multiband_amplifier)
|
||||
| | +--rw variety_list* string
|
||||
| +--:(Multiband_amplifier)
|
||||
| +--rw amplifiers* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw operational
|
||||
| +--rw gain_target? union
|
||||
| +--rw tilt_target? union
|
||||
| +--rw out_voa? union
|
||||
| +--rw in_voa? union
|
||||
| +--rw delta_p? union
|
||||
| +--rw f_min? decimal64
|
||||
| +--rw f_max? decimal64
|
||||
+--rw connections* [from_node to_node]
|
||||
| +--rw from_node -> ../../elements/uid
|
||||
| +--rw to_node -> ../../elements/uid
|
||||
+--rw network_name? string
|
||||
|
||||
augment /gapi:api:
|
||||
+--rw topology
|
||||
+--rw elements* [uid]
|
||||
| +--rw uid string
|
||||
| +--rw type identityref
|
||||
| +--rw type_variety? string
|
||||
| +--rw metadata
|
||||
| | +--rw location
|
||||
| | +--rw city? union
|
||||
| | +--rw region? union
|
||||
| | +--rw latitude? Coordinate
|
||||
| | +--rw longitude? Coordinate
|
||||
| +--rw operational
|
||||
| | +--rw (ramanfiber)?
|
||||
| | +--:(RamanFiber)
|
||||
| | | +--rw temperature? decimal64
|
||||
| | | +--rw raman_pumps* [frequency]
|
||||
| | | +--rw power? decimal64
|
||||
| | | +--rw frequency decimal64
|
||||
| | | +--rw propagation_direction? identityref
|
||||
| | +--:(Edfa)
|
||||
| | +--rw gain_target? union
|
||||
| | +--rw tilt_target? union
|
||||
| | +--rw out_voa? union
|
||||
| | +--rw in_voa? union
|
||||
| | +--rw delta_p? union
|
||||
| | +--rw f_min? decimal64
|
||||
| | +--rw f_max? decimal64
|
||||
| +--rw (element-type)?
|
||||
| +--:(FiberRoadm)
|
||||
| | +--rw params
|
||||
| | +--rw (fiberroadmfused)?
|
||||
| | +--:(Fiber)
|
||||
| | | +--rw length decimal64
|
||||
| | | +--rw pmd_coef? decimal64
|
||||
| | | +--rw (ref_freq_or_wl)?
|
||||
| | | | +--:(frequency)
|
||||
| | | | | +--rw ref_frequency? decimal64
|
||||
| | | | +--:(wavelength)
|
||||
| | | | +--rw ref_wavelength? decimal64
|
||||
| | | +--rw (dispersion-vector-or-scalar)?
|
||||
| | | | +--:(scalar)
|
||||
| | | | | +--rw dispersion? decimal64
|
||||
| | | | | +--rw dispersion_slope? decimal64
|
||||
| | | | +--:(vector)
|
||||
| | | | +--rw dispersion_per_frequency* [frequency]
|
||||
| | | | +--rw frequency decimal64
|
||||
| | | | +--rw dispersion? decimal64
|
||||
| | | +--rw effective_area? decimal64
|
||||
| | | +--rw gamma? decimal64
|
||||
| | | +--rw raman_coefficient
|
||||
| | | | +--rw reference_frequency? decimal64
|
||||
| | | | +--rw g0_per_frequency* [frequency_offset]
|
||||
| | | | +--rw frequency_offset decimal64
|
||||
| | | | +--rw g0? decimal64
|
||||
| | | +--rw lumped_losses* [position]
|
||||
| | | | +--rw position decimal64
|
||||
| | | | +--rw loss decimal64
|
||||
| | | +--rw (loss_coef-vector-or-scalar)?
|
||||
| | | | +--:(scalar)
|
||||
| | | | | +--rw loss_coef decimal64
|
||||
| | | | +--:(vector)
|
||||
| | | | +--rw loss_coef_per_frequency* [frequency]
|
||||
| | | | +--rw frequency decimal64
|
||||
| | | | +--rw loss_coef_value? decimal64
|
||||
| | | +--rw length_units identityref
|
||||
| | | +--rw att_in? decimal64
|
||||
| | | +--rw con_in? union
|
||||
| | | +--rw con_out? union
|
||||
| | +--:(RoadmTransceiver)
|
||||
| | | +--rw design_bands* [f_min]
|
||||
| | | | +--rw f_min decimal64
|
||||
| | | | +--rw f_max? decimal64
|
||||
| | | | +--rw (parameter-used-for-design)?
|
||||
| | | | +--:(spacing)
|
||||
| | | | | +--rw spacing? decimal64
|
||||
| | | | +--:(number-of-channels)
|
||||
| | | | +--rw number-of-channels? uint16
|
||||
| | | +--rw per_degree_design_bands_targets* [degree_uid]
|
||||
| | | | +--rw degree_uid -> ../../../../elements/uid
|
||||
| | | | +--rw design_bands* [f_min]
|
||||
| | | | +--rw f_min decimal64
|
||||
| | | | +--rw f_max? decimal64
|
||||
| | | | +--rw (parameter-used-for-design)?
|
||||
| | | | +--:(spacing)
|
||||
| | | | | +--rw spacing? decimal64
|
||||
| | | | +--:(number-of-channels)
|
||||
| | | | +--rw number-of-channels? uint16
|
||||
| | | +--rw (roadm)?
|
||||
| | | +--:(roadm)
|
||||
| | | +--rw (target_type)?
|
||||
| | | | +--:(constant_power)
|
||||
| | | | | +--rw target_pch_out_db? decimal64
|
||||
| | | | +--:(constant_psd)
|
||||
| | | | | +--rw target_psd_out_mWperGHz? decimal64
|
||||
| | | | +--:(constant_psw)
|
||||
| | | | +--rw target_out_mWperSlotWidth? decimal64
|
||||
| | | +--rw restrictions
|
||||
| | | | +--rw preamp_variety_list* string
|
||||
| | | | +--rw booster_variety_list* string
|
||||
| | | +--rw per_degree_power_targets* [degree_uid]
|
||||
| | | | +--rw degree_uid -> ../../../../elements/uid
|
||||
| | | | +--rw (per_degree_target_type)?
|
||||
| | | | +--:(constant_power)
|
||||
| | | | | +--rw per_degree_pch_out_db? decimal64
|
||||
| | | | +--:(constant_psd)
|
||||
| | | | | +--rw per_degree_psd_out_mWperGHz? decimal64
|
||||
| | | | +--:(constant_psw)
|
||||
| | | | +--rw per_degree_psd_out_mWperSlotWidth? decimal64
|
||||
| | | +--rw per_degree_impairments* [from_degree to_degree]
|
||||
| | | +--rw from_degree -> ../../../../elements/uid
|
||||
| | | +--rw to_degree -> ../../../../elements/uid
|
||||
| | | +--rw impairment_id? uint32
|
||||
| | +--:(Fused)
|
||||
| | | +--rw loss? union
|
||||
| | +--:(Multiband_amplifier)
|
||||
| | +--rw variety_list* string
|
||||
| +--:(Multiband_amplifier)
|
||||
| +--rw amplifiers* [type_variety]
|
||||
| +--rw type_variety string
|
||||
| +--rw operational
|
||||
| +--rw gain_target? union
|
||||
| +--rw tilt_target? union
|
||||
| +--rw out_voa? union
|
||||
| +--rw in_voa? union
|
||||
| +--rw delta_p? union
|
||||
| +--rw f_min? decimal64
|
||||
| +--rw f_max? decimal64
|
||||
+--rw connections* [from_node to_node]
|
||||
| +--rw from_node -> ../../elements/uid
|
||||
| +--rw to_node -> ../../elements/uid
|
||||
+--rw network_name? string
|
||||
877
gnpy/yang/gnpy-network-topology@2025-03-01.yang
Normal file
877
gnpy/yang/gnpy-network-topology@2025-03-01.yang
Normal file
@@ -0,0 +1,877 @@
|
||||
module gnpy-network-topology {
|
||||
yang-version 1.1;
|
||||
namespace "gnpy:gnpy-network-topology";
|
||||
prefix gnpynt;
|
||||
|
||||
import gnpy-api {
|
||||
prefix "gapi";
|
||||
revision-date 2025-06-13;
|
||||
}
|
||||
|
||||
import gnpy-eqpt-config {
|
||||
prefix "geqpt";
|
||||
revision-date 2025-05-26;
|
||||
}
|
||||
|
||||
organization
|
||||
"Telecom Infra Project OOPT PSE Working Group";
|
||||
contact
|
||||
"WG Web: <https://github.com/Telecominfraproject/oopt-gnpy>
|
||||
contact: <mailto:ahmed.triki@orange.com>
|
||||
contact: <mailto:esther.lerouzic@orange.com>
|
||||
";
|
||||
description
|
||||
"YANG model for gnpy network input for path computation - 2020 - candi preversion";
|
||||
|
||||
revision 2025-03-01 {
|
||||
description
|
||||
"spacing for design band and pmd_coef";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
|
||||
revision 2025-01-20 {
|
||||
description
|
||||
"Add RamanFiber, design bands, impairments";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
|
||||
revision 2024-02-21 {
|
||||
description
|
||||
"fix namespaces for identity-ref,
|
||||
add roadm impairment";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
revision 2023-02-01 {
|
||||
description
|
||||
"change per-degree roadm targets
|
||||
set 6 digits for fiber length
|
||||
set 6 digits for loss_coef
|
||||
add type empty for con_in and con_out";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
revision 2022-11-21 {
|
||||
description
|
||||
"draft for detecon - GNPy API";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
revision 2020-10-22 {
|
||||
description
|
||||
"draft for experimental/2020-candi";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
|
||||
identity type-element {
|
||||
description
|
||||
"Base identity for element type";
|
||||
}
|
||||
|
||||
identity Transceiver {
|
||||
base type-element;
|
||||
description
|
||||
" Transceiver element";
|
||||
}
|
||||
|
||||
identity Fiber {
|
||||
base type-element;
|
||||
description
|
||||
"Fiber element (unidirectional)";
|
||||
}
|
||||
|
||||
identity RamanFiber {
|
||||
base type-element;
|
||||
description
|
||||
"RamanFiber element (unidirectional)";
|
||||
}
|
||||
|
||||
identity Roadm {
|
||||
base type-element;
|
||||
description
|
||||
"Roadm element";
|
||||
}
|
||||
|
||||
identity Edfa {
|
||||
base type-element;
|
||||
description
|
||||
"Edfa element";
|
||||
}
|
||||
|
||||
identity Fused {
|
||||
base type-element;
|
||||
description
|
||||
"Fused element ; non amplified connection between two fiber spans ;
|
||||
can be used to model optical distribution frame, or losses due to
|
||||
connectors or fused in a span";
|
||||
}
|
||||
|
||||
identity Multiband_amplifier {
|
||||
base type-element;
|
||||
description
|
||||
"Multiband_amplifier element";
|
||||
}
|
||||
|
||||
identity length-unit {
|
||||
description
|
||||
"length unit";
|
||||
}
|
||||
|
||||
identity km {
|
||||
base length-unit;
|
||||
description
|
||||
"kilometers";
|
||||
}
|
||||
|
||||
identity m {
|
||||
base length-unit;
|
||||
description
|
||||
"meter";
|
||||
}
|
||||
|
||||
typedef Coordinate {
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
description
|
||||
"Latitude or longitude type";
|
||||
}
|
||||
|
||||
identity pumping-direction {
|
||||
description
|
||||
"Raman pumping direction";
|
||||
}
|
||||
|
||||
identity coprop {
|
||||
base pumping-direction;
|
||||
description
|
||||
"forward pumping";
|
||||
}
|
||||
|
||||
identity counterprop {
|
||||
base pumping-direction;
|
||||
description
|
||||
"backward pumping";
|
||||
}
|
||||
|
||||
grouping location-attributes {
|
||||
description
|
||||
"grouping for location imformation: city, region names
|
||||
and coordinates.";
|
||||
container location {
|
||||
description
|
||||
"Information for a node location: city, region names
|
||||
and coordinates.";
|
||||
leaf city {
|
||||
type union {
|
||||
type string;
|
||||
type empty;
|
||||
}
|
||||
description
|
||||
"City name.";
|
||||
}
|
||||
leaf region {
|
||||
type union {
|
||||
type string;
|
||||
type empty;
|
||||
}
|
||||
description
|
||||
"Region name. Used for filtering purpose.";
|
||||
}
|
||||
leaf latitude {
|
||||
type Coordinate;
|
||||
description
|
||||
"Latitude coordinate.";
|
||||
}
|
||||
leaf longitude {
|
||||
type Coordinate;
|
||||
description
|
||||
"Longitude coordinate.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping fiber-common-params {
|
||||
description
|
||||
"Common attributes to fiber and raman fiber.";
|
||||
leaf length {
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"Length of the fiber span.";
|
||||
}
|
||||
leaf pmd_coef {
|
||||
type decimal64 {
|
||||
fraction-digits 18;
|
||||
}
|
||||
units "s/km^0.5";
|
||||
description "PMD coefficient of the fiber span (s/km^0.5)";
|
||||
}
|
||||
|
||||
choice ref_freq_or_wl {
|
||||
description
|
||||
"Definition of the reference: frequency or wavelength.";
|
||||
case frequency {
|
||||
leaf ref_frequency {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
units "Hz";
|
||||
description
|
||||
"Reference frequency for all parameters evaluation
|
||||
(unique for all parameters: beta2, beta3, gamma, effective_area)";
|
||||
}
|
||||
}
|
||||
case wavelength {
|
||||
leaf ref_wavelength {
|
||||
type decimal64 {
|
||||
fraction-digits 12;
|
||||
}
|
||||
units "m";
|
||||
description
|
||||
"Reference wavelength for all parameters evaluation
|
||||
(unique for all parameters: beta2, beta3, gamma, effective_area)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
choice dispersion-vector-or-scalar {
|
||||
description
|
||||
"Dispersion definition: scalar with its slope or array of
|
||||
values and the slope is computed based on the values.";
|
||||
case scalar {
|
||||
leaf dispersion {
|
||||
type decimal64 {
|
||||
fraction-digits 8;
|
||||
}
|
||||
units "s.m-1.m-1";
|
||||
description "Dispersion of the span fiber.";
|
||||
}
|
||||
leaf dispersion_slope {
|
||||
type decimal64 {
|
||||
fraction-digits 11;
|
||||
}
|
||||
units "s.m-1.m-1.m-1";
|
||||
description "Dispersion slope of the span fiber.";
|
||||
}
|
||||
}
|
||||
case vector {
|
||||
list dispersion_per_frequency {
|
||||
key "frequency";
|
||||
description
|
||||
"Dispersion per frequency value.";
|
||||
leaf frequency {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
units "Hz";
|
||||
description "Frequency of the loss coef.";
|
||||
}
|
||||
leaf dispersion {
|
||||
type decimal64 {
|
||||
fraction-digits 8;
|
||||
}
|
||||
units "s.m-1.m-1";
|
||||
description "Dispersion of the span fiber.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf effective_area {
|
||||
type decimal64 {
|
||||
fraction-digits 14;
|
||||
}
|
||||
units "m^2";
|
||||
description "Effective Area of the span fibery.";
|
||||
}
|
||||
|
||||
leaf gamma{
|
||||
type decimal64 {
|
||||
fraction-digits 8;
|
||||
}
|
||||
units "w-1.m-1" ;
|
||||
description "2pi.n2/(lambda*Aeff) (w-2.m-1)";
|
||||
}
|
||||
|
||||
container raman_coefficient {
|
||||
description
|
||||
"Raman coeeficient definition (for Stimulated Raman Scattering
|
||||
and Raman amplification)";
|
||||
leaf reference_frequency {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
units "Hz";
|
||||
description
|
||||
"Reference frequency used with frequency offset values
|
||||
for Raman coefficient evaluation.";
|
||||
}
|
||||
list g0_per_frequency {
|
||||
key frequency_offset;
|
||||
description
|
||||
"Raman gain coefficient in terms of optical power defined per frequency.";
|
||||
leaf frequency_offset {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
units "Hz";
|
||||
description
|
||||
"Frequency offset.";
|
||||
}
|
||||
leaf g0 {
|
||||
type decimal64 {
|
||||
fraction-digits 14;
|
||||
}
|
||||
units "1/(m.W)";
|
||||
description "Raman gain coefficient in terms of optical power.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list lumped_losses {
|
||||
key "position";
|
||||
description "Places along the fiber length with extra
|
||||
losses. Specified as a loss in dB at each relevant position (in km).";
|
||||
leaf position {
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
units "km";
|
||||
mandatory true;
|
||||
description "Position of the lumped loss on the fiber.";
|
||||
}
|
||||
leaf loss {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
units "dB";
|
||||
mandatory true;
|
||||
description "Loss of the lumped loss on the fiber.";
|
||||
}
|
||||
}
|
||||
|
||||
choice loss_coef-vector-or-scalar {
|
||||
description
|
||||
"Loss coef definition: scalar or per frequency vector";
|
||||
case scalar {
|
||||
leaf loss_coef {
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
units "dB/km";
|
||||
mandatory true;
|
||||
description "Loss coefficient of the fiber span (dB/km)";
|
||||
}
|
||||
}
|
||||
case vector {
|
||||
list loss_coef_per_frequency {
|
||||
key frequency;
|
||||
description
|
||||
"Per frequency loss_coef definition.";
|
||||
leaf frequency {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
units "Hz";
|
||||
description
|
||||
"Frequency of the loss coef value.";
|
||||
}
|
||||
leaf loss_coef_value {
|
||||
type decimal64 {
|
||||
fraction-digits 16;
|
||||
}
|
||||
units "dB/km";
|
||||
description
|
||||
"Loss coef oat the frequency value.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf length_units {
|
||||
type identityref {
|
||||
base length-unit;
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"Length unit used for the length definition (m or km)";
|
||||
}
|
||||
leaf att_in {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"Padding attenuation placed at span input to reach min loss
|
||||
target defined in the library.";
|
||||
}
|
||||
leaf con_in {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"Input connector loss.";
|
||||
}
|
||||
leaf con_out {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"Output connector loss.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping raman-fiber-operational {
|
||||
description
|
||||
"Raman pumps definition of the Raman Fiber.";
|
||||
leaf temperature {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
description
|
||||
"Temperature of the fiber.";
|
||||
}
|
||||
list raman_pumps {
|
||||
description
|
||||
"Definition of Raman pumps.";
|
||||
key "frequency";
|
||||
leaf power {
|
||||
type decimal64 {
|
||||
fraction-digits 9;
|
||||
}
|
||||
units "W";
|
||||
description
|
||||
"Total pump power considering a depolarized pump.";
|
||||
}
|
||||
leaf frequency {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
units "Hz";
|
||||
description
|
||||
"Pump central frequency.";
|
||||
}
|
||||
leaf propagation_direction {
|
||||
type identityref {
|
||||
base pumping-direction;
|
||||
}
|
||||
description
|
||||
"Pump injection direction: the pumps can propagate in
|
||||
the same or opposite direction with respect the signal.
|
||||
Valid choices are coprop and counterprop";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping edfa-params {
|
||||
description
|
||||
"Common parameters for amplifiers definition.";
|
||||
leaf gain_target {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"gain target of the amplifier (before VOA and after att_in)";
|
||||
}
|
||||
leaf tilt_target {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"Tilt target on the whole wavelength range of the amplifier.";
|
||||
}
|
||||
leaf out_voa {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"Output variable optical attenuator loss";
|
||||
}
|
||||
leaf in_voa {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"Input variable optical attenuator loss";
|
||||
}
|
||||
leaf delta_p {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"Per channel target output power deviation with respect to power settings in SI.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping multiband-params {
|
||||
description
|
||||
"Attributes for multiband amplifiers";
|
||||
list amplifiers {
|
||||
key "type_variety";
|
||||
description
|
||||
"Definition of attributes of each amplifier of the multiband amplifier.";
|
||||
leaf type_variety {
|
||||
type string;
|
||||
description
|
||||
"Type_variety definition.";
|
||||
}
|
||||
container operational {
|
||||
description
|
||||
"Operational values for the Edfa ";
|
||||
uses edfa-params;
|
||||
uses geqpt:frequency-band;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping design-bands {
|
||||
description "Values used to compute the maximum power in
|
||||
amplifier during autodesign phase";
|
||||
choice parameter-used-for-design {
|
||||
description
|
||||
"Values used to compute the maximum power in
|
||||
amplifier during autodesign phase";
|
||||
case spacing {
|
||||
leaf spacing {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
units "Hz";
|
||||
description
|
||||
"Spacing used to compute max power in the spans
|
||||
during autodesign.";
|
||||
}
|
||||
}
|
||||
case number-of-channels {
|
||||
leaf number-of-channels {
|
||||
type uint16 {
|
||||
range "1 .. max";
|
||||
}
|
||||
description
|
||||
"Number of channels used to compute max power in the spans
|
||||
during autodesign.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping roadm-trx-params {
|
||||
description
|
||||
"Design band attributes common to ROADM and Transceivers,
|
||||
Used for autodesign";
|
||||
list design_bands {
|
||||
key "f_min";
|
||||
uses geqpt:frequency-band;
|
||||
uses design-bands;
|
||||
description
|
||||
"Value used to compute the maximum power in
|
||||
amplifier during autodesign phase, same for all degrees.";
|
||||
}
|
||||
list per_degree_design_bands_targets {
|
||||
key "degree_uid";
|
||||
description
|
||||
"Per degree definition of design bands used to compute the maximum power in
|
||||
amplifier during autodesign phase.";
|
||||
leaf degree_uid {
|
||||
type leafref {
|
||||
path "../../../../elements/uid";
|
||||
}
|
||||
description
|
||||
"Degree identifier (= uid of the next element on this direction).";
|
||||
}
|
||||
list design_bands {
|
||||
key "f_min";
|
||||
uses geqpt:frequency-band;
|
||||
uses design-bands;
|
||||
description
|
||||
"Value used to compute the maximum power in
|
||||
amplifier during autodesign phase, same for all degrees.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping roadm-params {
|
||||
description
|
||||
"Definition of ROADM configuration parameters.";
|
||||
uses geqpt:roadm-equalization-params;
|
||||
uses geqpt:restrictions;
|
||||
|
||||
list per_degree_power_targets {
|
||||
key "degree_uid";
|
||||
description
|
||||
"Equalization strategy for this degree. If not defined, use the
|
||||
one defined in ROADM.";
|
||||
leaf degree_uid {
|
||||
type leafref {
|
||||
path "../../../../elements/uid";
|
||||
}
|
||||
description
|
||||
"Degree identifier (= uid of the next element on this direction).";
|
||||
}
|
||||
choice per_degree_target_type {
|
||||
description
|
||||
"Equalization strategy for this ROADM. If not defined, the
|
||||
one defined in library for this type_variety is used.";
|
||||
case constant_power {
|
||||
leaf per_degree_pch_out_db {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
units "dBm";
|
||||
description
|
||||
"Equalization applied on all channels on this degree.
|
||||
This target replaces the one defined for all degrees";
|
||||
}
|
||||
}
|
||||
case constant_psd {
|
||||
leaf per_degree_psd_out_mWperGHz {
|
||||
type decimal64 {
|
||||
fraction-digits 10;
|
||||
}
|
||||
units "mW/GHz";
|
||||
description
|
||||
"Equalization applied on all channels on this degree.
|
||||
This target replaces the one defined for all degrees";
|
||||
}
|
||||
}
|
||||
case constant_psw {
|
||||
leaf per_degree_psd_out_mWperSlotWidth {
|
||||
type decimal64 {
|
||||
fraction-digits 10;
|
||||
}
|
||||
units "mW/GHz";
|
||||
description
|
||||
"Equalization applied on all channels on this degree.
|
||||
This target replaces the one defined for all degrees";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
list per_degree_impairments {
|
||||
key "from_degree to_degree";
|
||||
description
|
||||
"Definition of impairments for this ROADM.";
|
||||
leaf from_degree {
|
||||
type leafref {
|
||||
path "../../../../elements/uid";
|
||||
}
|
||||
description
|
||||
"Degree identifier (= uid of the next element on this direction).";
|
||||
}
|
||||
leaf to_degree {
|
||||
type leafref {
|
||||
path "../../../../elements/uid";
|
||||
}
|
||||
description
|
||||
"Degree identifier (= uid of the next element on this direction).";
|
||||
}
|
||||
leaf impairment_id {
|
||||
type uint32;
|
||||
description
|
||||
"Reference to the impairment ID defined in the library.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping fused-params{
|
||||
description
|
||||
"Parameters for Fused elements.";
|
||||
leaf loss {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units "dB";
|
||||
description
|
||||
"Concentrated loss of the fused element";
|
||||
}
|
||||
}
|
||||
|
||||
grouping element-type-choice {
|
||||
description
|
||||
"Definition of operational container for RamanFiber or Edfa, and of
|
||||
params container for all elements.";
|
||||
container operational {
|
||||
when "../type = 'gnpynt:Edfa' or ../type = 'gnpynt:RamanFiber'";
|
||||
description
|
||||
"Operational values for the Edfa and the RamanFiber";
|
||||
choice ramanfiber {
|
||||
description
|
||||
"Definition of operational parameters for RamanFibers";
|
||||
case RamanFiber {
|
||||
when "../type = 'gnpynt:RamanFiber'";
|
||||
uses raman-fiber-operational;
|
||||
}
|
||||
case Edfa {
|
||||
when "../type = 'gnpynt:Edfa'";
|
||||
uses edfa-params;
|
||||
uses geqpt:frequency-band;
|
||||
}
|
||||
}
|
||||
}
|
||||
choice element-type {
|
||||
description
|
||||
"Params content depending on element type.";
|
||||
case FiberRoadm {
|
||||
container params {
|
||||
description
|
||||
"parameters definition in case of Fiber, RamanFiber, Roadm, Fused, Transceivers";
|
||||
choice fiberroadmfused {
|
||||
description
|
||||
"parameters definition in case of Fiber, RamanFiber, Roadm, Fused, Transceivers";
|
||||
case Fiber {
|
||||
when "../type = 'gnpynt:Fiber' or ../type = 'gnpynt:RamanFiber'";
|
||||
uses fiber-common-params;
|
||||
}
|
||||
case RoadmTransceiver {
|
||||
when "../type = 'gnpynt:Roadm' or ../type = 'gnpynt:Transceiver'";
|
||||
uses roadm-trx-params;
|
||||
choice roadm {
|
||||
description
|
||||
"parameters definition only in case of Roadm.";
|
||||
case roadm {
|
||||
when "../type = 'gnpynt:Roadm'";
|
||||
uses roadm-params;
|
||||
}
|
||||
}
|
||||
}
|
||||
case Fused {
|
||||
when "../type = 'gnpynt:Fused'";
|
||||
uses fused-params;
|
||||
}
|
||||
case Multiband_amplifier {
|
||||
when "../type = 'gnpynt:Multiband_amplifier'";
|
||||
leaf-list variety_list {
|
||||
type string;
|
||||
description
|
||||
"List of authorized type-variety";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case Multiband_amplifier {
|
||||
when "type = 'gnpynt:Multiband_amplifier'";
|
||||
uses multiband-params;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
grouping topo {
|
||||
description
|
||||
"Definition of the topology: list of elements and connections.";
|
||||
list elements {
|
||||
description
|
||||
"element definition.";
|
||||
key "uid";
|
||||
leaf uid {
|
||||
type string;
|
||||
description
|
||||
"element unique identifier";
|
||||
}
|
||||
leaf type {
|
||||
type identityref {
|
||||
base type-element;
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"element type among possible types (Fiber, RamanFiber, Edfa,
|
||||
Multiband_amplifier, Fused, Roadm, Transceiver).";
|
||||
}
|
||||
leaf type_variety {
|
||||
type string;
|
||||
description
|
||||
"Valid reference to a library reference type variety for (Fiber,
|
||||
RamanFiber, Edfa, Multiband_amplifier, Roadm).";
|
||||
}
|
||||
container metadata {
|
||||
description
|
||||
"Metadata definitions.";
|
||||
uses location-attributes;
|
||||
}
|
||||
uses element-type-choice;
|
||||
}
|
||||
list connections {
|
||||
key "from_node to_node";
|
||||
description
|
||||
"List on connections between elements.";
|
||||
leaf from_node {
|
||||
type leafref {
|
||||
path "../../elements/uid";
|
||||
}
|
||||
description
|
||||
"Ingress node of the connection, reference to a defined element in the topology";
|
||||
}
|
||||
leaf to_node {
|
||||
type leafref {
|
||||
path "../../elements/uid";
|
||||
}
|
||||
description
|
||||
"Egress node of the connection, reference to a defined element in the topology";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping gnpytopo {
|
||||
description
|
||||
"Reusable grouping for topology definition.";
|
||||
container topology {
|
||||
description
|
||||
"Describe the topology gnpy-formated for release 2.6 toaster (including mixed rate and multiband)";
|
||||
uses topo;
|
||||
leaf network_name {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container topology {
|
||||
description
|
||||
"Describe the topology gnpy-formated for release 2.6 toaster (including mixed rate and multiband)";
|
||||
uses topo;
|
||||
leaf network_name {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
|
||||
augment "/gapi:api" {
|
||||
description "Add the gnpy-network-topology input in the API request.";
|
||||
uses gnpytopo;
|
||||
}
|
||||
}
|
||||
235
gnpy/yang/gnpy-path-computation@2025-01-20.tree
Normal file
235
gnpy/yang/gnpy-path-computation@2025-01-20.tree
Normal file
@@ -0,0 +1,235 @@
|
||||
module: gnpy-path-computation
|
||||
+--rw services
|
||||
| +--rw path-request* [request-id]
|
||||
| | +--rw request-id string
|
||||
| | +--rw bidirectional boolean
|
||||
| | +--rw source? string
|
||||
| | +--rw destination? string
|
||||
| | +--rw src-tp-id? string
|
||||
| | +--rw dst-tp-id? string
|
||||
| | +--rw explicit-route-objects
|
||||
| | | +--ro route-object-include-exclude* [index]
|
||||
| | | +--ro explicit-route-usage? identityref
|
||||
| | | +--ro index uint32
|
||||
| | | +--ro (subobject-type)?
|
||||
| | | +--:(num-unnum-hop)
|
||||
| | | | +--ro num-unnum-hop
|
||||
| | | | +--ro node-id? string
|
||||
| | | | +--ro link-tp-id? string
|
||||
| | | | +--ro hop-type? te-hop-type
|
||||
| | | +--:(label)
|
||||
| | | | +--ro label-hop* [N]
|
||||
| | | | +--ro N union
|
||||
| | | | +--ro M? union
|
||||
| | | +--:(hop-attribute)
|
||||
| | | +--ro (hop-type)?
|
||||
| | | +--:(tsp)
|
||||
| | | | +--ro transponder
|
||||
| | | | +--ro transponder-type? string
|
||||
| | | | +--ro transponder-mode? string
|
||||
| | | +--:(regen)
|
||||
| | | +--ro regenerator
|
||||
| | | +--ro transponder-type? string
|
||||
| | | +--ro transponder-mode? string
|
||||
| | +--rw path-constraints
|
||||
| | +--rw te-bandwidth
|
||||
| | +--rw technology? string
|
||||
| | +--rw trx_type string
|
||||
| | +--rw trx_mode? union
|
||||
| | +--rw effective-freq-slot* [N]
|
||||
| | | +--rw N union
|
||||
| | | +--rw M? union
|
||||
| | +--rw spacing decimal64
|
||||
| | +--rw max-nb-of-channel? union
|
||||
| | +--rw output-power? union
|
||||
| | +--rw tx_power? union
|
||||
| | +--rw path_bandwidth decimal64
|
||||
| +--rw synchronization* [synchronization-id]
|
||||
| +--rw synchronization-id string
|
||||
| +--rw svec
|
||||
| +--rw relaxable? boolean
|
||||
| +--rw disjointness? te-path-disjointness
|
||||
| +--rw request-id-number* string
|
||||
+--rw responses
|
||||
+--rw response* [response-id]
|
||||
+--rw response-id string
|
||||
+--rw path-properties
|
||||
| +--rw path-metric* [metric-type]
|
||||
| | +--rw metric-type identityref
|
||||
| | +--rw accumulative-value? union
|
||||
| +--rw z-a-path-metric* [metric-type]
|
||||
| | +--rw metric-type identityref
|
||||
| | +--rw accumulative-value? union
|
||||
| +--ro path-route-objects* []
|
||||
| +--ro path-route-object
|
||||
| +--ro index? uint32
|
||||
| +--ro (subobject-type)?
|
||||
| +--:(num-unnum-hop)
|
||||
| | +--ro num-unnum-hop
|
||||
| | +--ro node-id? string
|
||||
| | +--ro link-tp-id? string
|
||||
| | +--ro hop-type? te-hop-type
|
||||
| +--:(label)
|
||||
| | +--ro label-hop* [N]
|
||||
| | +--ro N union
|
||||
| | +--ro M? union
|
||||
| +--:(hop-attribute)
|
||||
| +--ro (hop-type)?
|
||||
| +--:(tsp)
|
||||
| | +--ro transponder
|
||||
| | +--ro transponder-type? string
|
||||
| | +--ro transponder-mode? string
|
||||
| +--:(regen)
|
||||
| +--ro regenerator
|
||||
| +--ro transponder-type? string
|
||||
| +--ro transponder-mode? string
|
||||
+--rw no-path
|
||||
+--rw no-path? identityref
|
||||
+--rw path-properties
|
||||
+--rw path-metric* [metric-type]
|
||||
| +--rw metric-type identityref
|
||||
| +--rw accumulative-value? union
|
||||
+--rw z-a-path-metric* [metric-type]
|
||||
| +--rw metric-type identityref
|
||||
| +--rw accumulative-value? union
|
||||
+--ro path-route-objects* []
|
||||
+--ro path-route-object
|
||||
+--ro index? uint32
|
||||
+--ro (subobject-type)?
|
||||
+--:(num-unnum-hop)
|
||||
| +--ro num-unnum-hop
|
||||
| +--ro node-id? string
|
||||
| +--ro link-tp-id? string
|
||||
| +--ro hop-type? te-hop-type
|
||||
+--:(label)
|
||||
| +--ro label-hop* [N]
|
||||
| +--ro N union
|
||||
| +--ro M? union
|
||||
+--:(hop-attribute)
|
||||
+--ro (hop-type)?
|
||||
+--:(tsp)
|
||||
| +--ro transponder
|
||||
| +--ro transponder-type? string
|
||||
| +--ro transponder-mode? string
|
||||
+--:(regen)
|
||||
+--ro regenerator
|
||||
+--ro transponder-type? string
|
||||
+--ro transponder-mode? string
|
||||
|
||||
augment /gapi:api:
|
||||
+--rw services
|
||||
| +--rw path-request* [request-id]
|
||||
| | +--rw request-id string
|
||||
| | +--rw bidirectional boolean
|
||||
| | +--rw source? string
|
||||
| | +--rw destination? string
|
||||
| | +--rw src-tp-id? string
|
||||
| | +--rw dst-tp-id? string
|
||||
| | +--rw explicit-route-objects
|
||||
| | | +--ro route-object-include-exclude* [index]
|
||||
| | | +--ro explicit-route-usage? identityref
|
||||
| | | +--ro index uint32
|
||||
| | | +--ro (subobject-type)?
|
||||
| | | +--:(num-unnum-hop)
|
||||
| | | | +--ro num-unnum-hop
|
||||
| | | | +--ro node-id? string
|
||||
| | | | +--ro link-tp-id? string
|
||||
| | | | +--ro hop-type? te-hop-type
|
||||
| | | +--:(label)
|
||||
| | | | +--ro label-hop* [N]
|
||||
| | | | +--ro N union
|
||||
| | | | +--ro M? union
|
||||
| | | +--:(hop-attribute)
|
||||
| | | +--ro (hop-type)?
|
||||
| | | +--:(tsp)
|
||||
| | | | +--ro transponder
|
||||
| | | | +--ro transponder-type? string
|
||||
| | | | +--ro transponder-mode? string
|
||||
| | | +--:(regen)
|
||||
| | | +--ro regenerator
|
||||
| | | +--ro transponder-type? string
|
||||
| | | +--ro transponder-mode? string
|
||||
| | +--rw path-constraints
|
||||
| | +--rw te-bandwidth
|
||||
| | +--rw technology? string
|
||||
| | +--rw trx_type string
|
||||
| | +--rw trx_mode? union
|
||||
| | +--rw effective-freq-slot* [N]
|
||||
| | | +--rw N union
|
||||
| | | +--rw M? union
|
||||
| | +--rw spacing decimal64
|
||||
| | +--rw max-nb-of-channel? union
|
||||
| | +--rw output-power? union
|
||||
| | +--rw tx_power? union
|
||||
| | +--rw path_bandwidth decimal64
|
||||
| +--rw synchronization* [synchronization-id]
|
||||
| +--rw synchronization-id string
|
||||
| +--rw svec
|
||||
| +--rw relaxable? boolean
|
||||
| +--rw disjointness? te-path-disjointness
|
||||
| +--rw request-id-number* string
|
||||
+--rw responses
|
||||
+--rw response* [response-id]
|
||||
+--rw response-id string
|
||||
+--rw path-properties
|
||||
| +--rw path-metric* [metric-type]
|
||||
| | +--rw metric-type identityref
|
||||
| | +--rw accumulative-value? union
|
||||
| +--rw z-a-path-metric* [metric-type]
|
||||
| | +--rw metric-type identityref
|
||||
| | +--rw accumulative-value? union
|
||||
| +--ro path-route-objects* []
|
||||
| +--ro path-route-object
|
||||
| +--ro index? uint32
|
||||
| +--ro (subobject-type)?
|
||||
| +--:(num-unnum-hop)
|
||||
| | +--ro num-unnum-hop
|
||||
| | +--ro node-id? string
|
||||
| | +--ro link-tp-id? string
|
||||
| | +--ro hop-type? te-hop-type
|
||||
| +--:(label)
|
||||
| | +--ro label-hop* [N]
|
||||
| | +--ro N union
|
||||
| | +--ro M? union
|
||||
| +--:(hop-attribute)
|
||||
| +--ro (hop-type)?
|
||||
| +--:(tsp)
|
||||
| | +--ro transponder
|
||||
| | +--ro transponder-type? string
|
||||
| | +--ro transponder-mode? string
|
||||
| +--:(regen)
|
||||
| +--ro regenerator
|
||||
| +--ro transponder-type? string
|
||||
| +--ro transponder-mode? string
|
||||
+--rw no-path
|
||||
+--rw no-path? identityref
|
||||
+--rw path-properties
|
||||
+--rw path-metric* [metric-type]
|
||||
| +--rw metric-type identityref
|
||||
| +--rw accumulative-value? union
|
||||
+--rw z-a-path-metric* [metric-type]
|
||||
| +--rw metric-type identityref
|
||||
| +--rw accumulative-value? union
|
||||
+--ro path-route-objects* []
|
||||
+--ro path-route-object
|
||||
+--ro index? uint32
|
||||
+--ro (subobject-type)?
|
||||
+--:(num-unnum-hop)
|
||||
| +--ro num-unnum-hop
|
||||
| +--ro node-id? string
|
||||
| +--ro link-tp-id? string
|
||||
| +--ro hop-type? te-hop-type
|
||||
+--:(label)
|
||||
| +--ro label-hop* [N]
|
||||
| +--ro N union
|
||||
| +--ro M? union
|
||||
+--:(hop-attribute)
|
||||
+--ro (hop-type)?
|
||||
+--:(tsp)
|
||||
| +--ro transponder
|
||||
| +--ro transponder-type? string
|
||||
| +--ro transponder-mode? string
|
||||
+--:(regen)
|
||||
+--ro regenerator
|
||||
+--ro transponder-type? string
|
||||
+--ro transponder-mode? string
|
||||
728
gnpy/yang/gnpy-path-computation@2025-01-20.yang
Normal file
728
gnpy/yang/gnpy-path-computation@2025-01-20.yang
Normal file
@@ -0,0 +1,728 @@
|
||||
module gnpy-path-computation {
|
||||
yang-version 1.1;
|
||||
namespace "gnpy:gnpy-path-computation";
|
||||
|
||||
prefix "gnpypc";
|
||||
|
||||
import gnpy-api {
|
||||
prefix "gapi";
|
||||
revision-date 2025-06-13;
|
||||
}
|
||||
|
||||
organization
|
||||
"Telecom Infra Project OOPT PSE Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://github.com/Telecominfraproject/oopt-gnpy>
|
||||
contact: <mailto:ahmed.triki@orange.com>
|
||||
contact: <mailto:esther.lerouzic@orange.com>
|
||||
";
|
||||
|
||||
description "YANG model for gnpy path computation simplified for - 2020 - candi preversion";
|
||||
|
||||
revision "2025-01-20" {
|
||||
description
|
||||
"Add tx_power";
|
||||
reference
|
||||
"YANG model for path computation with gnpy inputs";
|
||||
}
|
||||
|
||||
revision "2022-12-01" {
|
||||
description
|
||||
"draft for detecon - GNPy API";
|
||||
reference
|
||||
"YANG model for path computation with gnpy inputs";
|
||||
}
|
||||
|
||||
grouping effective-freq-slot{
|
||||
/* content copied from ietf-flexi-grid-media-channel, because only M and N are needed
|
||||
from the initial grouping.
|
||||
*/
|
||||
description "The effective frequency slot is an attribute
|
||||
of a media channel and, being a frequency slot, it is
|
||||
described by its nominal central frequency and slot
|
||||
width";
|
||||
reference "rfc7698";
|
||||
leaf N {
|
||||
type union {
|
||||
type int32;
|
||||
type empty;
|
||||
}
|
||||
description
|
||||
"Is used to determine the Nominal Central
|
||||
Frequency. The set of nominal central frequencies
|
||||
can be built using the following expression:
|
||||
f = 193.1 THz + n x 0.00625 THz,
|
||||
where 193.1 THz is ITU-T ''anchor frequency'' for
|
||||
transmission over the C band, n is a positive or
|
||||
negative integer including 0.";
|
||||
reference "rfc7698";
|
||||
}
|
||||
leaf M {
|
||||
type union {
|
||||
type uint32;
|
||||
type empty;
|
||||
}
|
||||
description
|
||||
"Is used to determine the slot width. A slot width
|
||||
is constrained to be M x SWG (that is, M x 12.5 GHz),
|
||||
where M is an integer greater than or equal to 1.";
|
||||
reference "rfc7698";
|
||||
}
|
||||
}
|
||||
|
||||
grouping gnpy-specific-parameters{
|
||||
description
|
||||
"This grouping defines the gnpy specific parameters for requests.";
|
||||
leaf technology {
|
||||
type string;
|
||||
default "flexi-grid";
|
||||
description
|
||||
"Data plane technology type.";
|
||||
}
|
||||
leaf trx_type {
|
||||
type string ;
|
||||
mandatory true;
|
||||
description "name of the transceiver type (to be read from equipment library";
|
||||
|
||||
}
|
||||
leaf trx_mode {
|
||||
type union {
|
||||
type string;
|
||||
type empty;
|
||||
}
|
||||
description "name of the transceiver mode (to be read from equipment library";
|
||||
}
|
||||
list effective-freq-slot {
|
||||
key "N";
|
||||
description
|
||||
"Definition of a list of frequency slots using n and m values (ITU T G694.1)";
|
||||
uses effective-freq-slot ;
|
||||
}
|
||||
leaf spacing {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
units Hz;
|
||||
mandatory true;
|
||||
description
|
||||
"It is the spacing between channels assuming full load with
|
||||
same channels as the requested one. multiple of 12.5 GHz";
|
||||
|
||||
}
|
||||
leaf max-nb-of-channel{
|
||||
type union {
|
||||
type int32;
|
||||
type empty;
|
||||
}
|
||||
description "Nb of channel to take into account for the full load case.
|
||||
";
|
||||
|
||||
}
|
||||
leaf output-power{
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 8;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units W;
|
||||
description "optical power setting to be used for the propagation";
|
||||
|
||||
}
|
||||
leaf tx_power{
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 5;
|
||||
}
|
||||
type empty;
|
||||
}
|
||||
units W;
|
||||
description "optical power out of transceiver";
|
||||
|
||||
}
|
||||
leaf path_bandwidth{
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
units bit/s;
|
||||
mandatory true;
|
||||
description "Capacity required";
|
||||
}
|
||||
}
|
||||
|
||||
identity SNR-bandwidth {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records SNR in signal bandwidth";
|
||||
}
|
||||
|
||||
identity OSNR-bandwidth {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records OSNR in signal bandwidth";
|
||||
}
|
||||
|
||||
identity SNR-0.1nm {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records SNR in 0.1nm";
|
||||
}
|
||||
|
||||
identity OSNR-0.1nm {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records OSNR in 0.1nm";
|
||||
}
|
||||
|
||||
identity lowest_SNR-0.1nm {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records the lowest SNR in 0.1nm in spectrum";
|
||||
}
|
||||
|
||||
identity biggest_SNR-0.1nm {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records the lowest SNR in 0.1nm in spectrum";
|
||||
}
|
||||
|
||||
identity PDL_penalty {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records the PDL penalty.";
|
||||
}
|
||||
|
||||
identity PMD_penalty {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records the PMD penalty.";
|
||||
}
|
||||
|
||||
identity CD_penalty {
|
||||
base path-metric-type;
|
||||
description
|
||||
"A metric that records the CD penalty.";
|
||||
}
|
||||
|
||||
identity reference_power {
|
||||
base path-metric-type;
|
||||
description
|
||||
"to be revised";
|
||||
}
|
||||
|
||||
identity path_bandwidth {
|
||||
base path-metric-type;
|
||||
description
|
||||
"to be revised";
|
||||
}
|
||||
|
||||
grouping transponder{
|
||||
description
|
||||
"Transponder type and mode used in the hop.";
|
||||
leaf transponder-type {
|
||||
type string ;
|
||||
description
|
||||
"transceiver type.";
|
||||
}
|
||||
leaf transponder-mode {
|
||||
type string ;
|
||||
description
|
||||
"transceiver mode.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping hop-attribute{
|
||||
description
|
||||
"This grouping defines the hop attribute parameters for request or response";
|
||||
choice hop-type{
|
||||
description
|
||||
"Hop may be a regenerator or a terminal.";
|
||||
case tsp {
|
||||
container transponder {
|
||||
description
|
||||
"Transponder hop in the path. (at source and at destination)";
|
||||
uses transponder ;
|
||||
}
|
||||
}
|
||||
case regen {
|
||||
container regenerator{
|
||||
description
|
||||
"Regenerator hop in the path.";
|
||||
uses transponder ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
identity no-path-type {
|
||||
description
|
||||
"base for blocking reasons";
|
||||
}
|
||||
|
||||
identity NO_PATH {
|
||||
base no-path-type;
|
||||
description
|
||||
"Cause of feasibility failure: no path could be computed.";
|
||||
|
||||
}
|
||||
|
||||
identity NO_PATH_WITH_CONSTRAINT {
|
||||
base no-path-type;
|
||||
description
|
||||
"Cause of feasibility failure: no path can meet the includec
|
||||
node constraint.";
|
||||
|
||||
}
|
||||
|
||||
identity NO_FEASIBLE_BAUDRATE_WITH_SPACING {
|
||||
base no-path-type;
|
||||
description
|
||||
"Cause of feasibility failure: no mode can fit in the
|
||||
requested spectrum.";
|
||||
}
|
||||
|
||||
identity NO_COMPUTED_SNR {
|
||||
base no-path-type;
|
||||
description
|
||||
"Cause of feasibility failure: requests SNR performance
|
||||
could not be computed";
|
||||
}
|
||||
|
||||
identity MODE_NOT_FEASIBLE {
|
||||
base no-path-type;
|
||||
description
|
||||
"Cause of feasibility failure: requested mode does not provide
|
||||
enough performance for this path.";
|
||||
|
||||
}
|
||||
|
||||
identity NO_FEASIBLE_MODE {
|
||||
base no-path-type;
|
||||
description
|
||||
"Cause of feasibility failure: no mode of this transceiver
|
||||
can achieve enough performance for the path.";
|
||||
|
||||
}
|
||||
|
||||
identity NO_SPECTRUM {
|
||||
base no-path-type;
|
||||
description
|
||||
"Cause of feasibility failure: requests requires more spectrum
|
||||
than the actual available spectrum on the path.";
|
||||
}
|
||||
|
||||
identity NOT_ENOUGH_RESERVED_SPECTRUM {
|
||||
base no-path-type;
|
||||
description
|
||||
"Cause of feasibility failure: signal requires more spectrum
|
||||
than the one defined in the request.";
|
||||
}
|
||||
|
||||
|
||||
identity path-metric-type {
|
||||
description
|
||||
"Base identity for path metric type";
|
||||
}
|
||||
|
||||
identity route-usage-type {
|
||||
description
|
||||
"Base identity for route usage";
|
||||
}
|
||||
|
||||
identity route-include-ero {
|
||||
base route-usage-type;
|
||||
description
|
||||
"Include ERO from route";
|
||||
}
|
||||
|
||||
identity route-exclude-ero {
|
||||
base route-usage-type;
|
||||
description
|
||||
"Exclude ERO from route";
|
||||
}
|
||||
|
||||
identity route-exclude-srlg {
|
||||
base route-usage-type;
|
||||
description
|
||||
"Exclude SRLG from route";
|
||||
}
|
||||
|
||||
typedef te-hop-type {
|
||||
type enumeration {
|
||||
enum LOOSE {
|
||||
description
|
||||
"loose hop in an explicit path";
|
||||
}
|
||||
enum STRICT {
|
||||
description
|
||||
"strict hop in an explicit path";
|
||||
}
|
||||
}
|
||||
description
|
||||
"enumerated type for specifying loose or strict
|
||||
paths";
|
||||
reference "RFC3209: section-4.3.2";
|
||||
}
|
||||
|
||||
typedef te-path-disjointness {
|
||||
type bits {
|
||||
bit node {
|
||||
position 0;
|
||||
description "Node disjoint.";
|
||||
}
|
||||
bit link {
|
||||
position 1;
|
||||
description "Link disjoint.";
|
||||
}
|
||||
bit srlg {
|
||||
position 2;
|
||||
description "SRLG (Shared Risk Link Group) disjoint.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Type of the resource disjointness for a TE tunnel path.";
|
||||
reference
|
||||
"RFC4872: RSVP-TE Extensions in Support of End-to-End
|
||||
Generalized Multi-Protocol Label Switching (GMPLS)
|
||||
Recovery";
|
||||
} // te-path-disjointness
|
||||
|
||||
typedef accumulated-metric-type {
|
||||
type union {
|
||||
type uint64;
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
}
|
||||
description
|
||||
"type useable for accumulative-value";
|
||||
}
|
||||
|
||||
grouping path-route-objects {
|
||||
description
|
||||
"List of EROs to be included or excluded when performing
|
||||
the path computation.";
|
||||
container explicit-route-objects {
|
||||
description
|
||||
"Container for the route object list";
|
||||
list route-object-include-exclude {
|
||||
key "index";
|
||||
config false;
|
||||
description
|
||||
"List of explicit route objects to include or
|
||||
exclude in path computation";
|
||||
leaf explicit-route-usage {
|
||||
type identityref {
|
||||
base route-usage-type;
|
||||
}
|
||||
description "Explicit-route usage.";
|
||||
}
|
||||
uses explicit-route-hop ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping generic-path-disjointness {
|
||||
description "Path disjointness grouping";
|
||||
leaf disjointness {
|
||||
type te-path-disjointness;
|
||||
description
|
||||
"The type of resource disjointness.
|
||||
Under primary path, disjointness level applies to
|
||||
all secondary LSPs. Under secondary, disjointness
|
||||
level overrides the one under primary";
|
||||
}
|
||||
}
|
||||
|
||||
grouping common-path-constraints-attributes {
|
||||
description
|
||||
"Common path constraints configuration grouping";
|
||||
uses common-constraints_config;
|
||||
}
|
||||
|
||||
grouping generic-path-constraints {
|
||||
description
|
||||
"Global named path constraints configuration
|
||||
grouping";
|
||||
container path-constraints {
|
||||
description "TE named path constraints container";
|
||||
uses common-path-constraints-attributes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
grouping explicit-route-hop {
|
||||
description
|
||||
"The explicit route subobject grouping";
|
||||
leaf index {
|
||||
type uint32;
|
||||
description "ERO subobject index";
|
||||
}
|
||||
choice subobject-type {
|
||||
description
|
||||
"The explicit route subobject type";
|
||||
case num-unnum-hop {
|
||||
container num-unnum-hop {
|
||||
leaf node-id {
|
||||
//type te-node-id;
|
||||
type string;
|
||||
description
|
||||
"The identifier of a node in the TE topology.";
|
||||
}
|
||||
leaf link-tp-id {
|
||||
//type te-tp-id;
|
||||
type string;
|
||||
description
|
||||
"TE link termination point identifier. The combination
|
||||
of TE link ID and the TE node ID is used to identify an
|
||||
unnumbered TE link.";
|
||||
}
|
||||
leaf hop-type {
|
||||
type te-hop-type;
|
||||
description "strict or loose hop";
|
||||
}
|
||||
description
|
||||
"Numbered and Unnumbered link/node explicit route
|
||||
subobject";
|
||||
}
|
||||
}
|
||||
case label {
|
||||
list label-hop {
|
||||
key "N";
|
||||
config false;
|
||||
description "Label hop type";
|
||||
uses effective-freq-slot;
|
||||
}
|
||||
description
|
||||
"The Label ERO subobject";
|
||||
}
|
||||
case hop-attribute{
|
||||
uses gnpypc:hop-attribute ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping common-constraints_config {
|
||||
description
|
||||
"Common constraints grouping that can be set on
|
||||
a constraint set or directly on the tunnel";
|
||||
|
||||
container te-bandwidth {
|
||||
uses gnpy-specific-parameters ;
|
||||
description
|
||||
"A requested bandwidth to use for path computation";
|
||||
}
|
||||
}
|
||||
|
||||
grouping end-points {
|
||||
description
|
||||
"Common grouping to define the TE tunnel end-points";
|
||||
|
||||
leaf source {
|
||||
type string;
|
||||
description "TE tunnel source address.";
|
||||
}
|
||||
leaf destination {
|
||||
type string;
|
||||
description "P2P tunnel destination address";
|
||||
}
|
||||
leaf src-tp-id {
|
||||
type string;
|
||||
description "TE tunnel source termination point identifier.";
|
||||
}
|
||||
leaf dst-tp-id {
|
||||
type string;
|
||||
description "TE tunnel destination termination point
|
||||
identifier.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping synchronization-info {
|
||||
description "Information for sync";
|
||||
list synchronization {
|
||||
key "synchronization-id";
|
||||
description "sync list";
|
||||
leaf synchronization-id {
|
||||
type string;
|
||||
description "index";
|
||||
}
|
||||
container svec {
|
||||
description
|
||||
"Synchronization VECtor";
|
||||
leaf relaxable {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"If this leaf is true, path computation process is free
|
||||
to ignore svec content.
|
||||
otherwise it must take into account this svec.";
|
||||
}
|
||||
uses generic-path-disjointness;
|
||||
leaf-list request-id-number {
|
||||
type string;
|
||||
description "This list reports the set of M path computation requests that must be synchronized.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping service {
|
||||
description
|
||||
"reusable grouping for path computation requests.";
|
||||
|
||||
list path-request {
|
||||
key "request-id";
|
||||
description "request-list";
|
||||
leaf request-id {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Each path computation request is uniquely identified by the request-id-number.";
|
||||
}
|
||||
leaf bidirectional {
|
||||
type boolean;
|
||||
mandatory true;
|
||||
description "Specify the bidirectionality of the path";
|
||||
}
|
||||
|
||||
uses end-points;
|
||||
uses path-route-objects;
|
||||
uses generic-path-constraints;
|
||||
}
|
||||
uses synchronization-info;
|
||||
}
|
||||
|
||||
grouping accumulated-metric-object {
|
||||
description
|
||||
"Reusable grouping for performance metrics.";
|
||||
leaf metric-type {
|
||||
type identityref {
|
||||
base path-metric-type;
|
||||
}
|
||||
description
|
||||
"Metric type.";
|
||||
}
|
||||
leaf accumulative-value {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 8;
|
||||
}
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
type string;
|
||||
type empty;
|
||||
}
|
||||
description
|
||||
"Accumulative value.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping response-path-property {
|
||||
description
|
||||
"Reusable grouping for responses of a path computation request.";
|
||||
list path-metric {
|
||||
key metric-type;
|
||||
description
|
||||
"List of accumulated metrics at the end of the path.";
|
||||
uses accumulated-metric-object;
|
||||
}
|
||||
list z-a-path-metric {
|
||||
key metric-type;
|
||||
description
|
||||
"List of accumulated metrics at the end of the path.";
|
||||
uses accumulated-metric-object;
|
||||
}
|
||||
}
|
||||
|
||||
grouping response-path-route-object {
|
||||
description
|
||||
"Definition of the explicit path of one response";
|
||||
list path-route-objects {
|
||||
config false;
|
||||
description
|
||||
"List of the explicit path hops.";
|
||||
container path-route-object {
|
||||
description
|
||||
"Definition of the hop.";
|
||||
uses explicit-route-hop ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping response {
|
||||
description
|
||||
"Reusable grouping for path computation response.";
|
||||
list response {
|
||||
key response-id;
|
||||
description
|
||||
"List of responses for the path-computation request.";
|
||||
leaf response-id {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Each path computation response is uniquely identified by the response-id number.";
|
||||
}
|
||||
container path-properties {
|
||||
description
|
||||
"Definition of the content of the successful response";
|
||||
uses response-path-property;
|
||||
uses response-path-route-object;
|
||||
}
|
||||
container no-path {
|
||||
description
|
||||
"Definition of the content of the response when feasibility is not achieved.";
|
||||
leaf no-path {
|
||||
type identityref {
|
||||
base no-path-type;
|
||||
}
|
||||
description
|
||||
"Detailed reason for feasibility failure.";
|
||||
}
|
||||
container path-properties {
|
||||
description
|
||||
"Definition of the content of the failed response";
|
||||
uses response-path-property;
|
||||
uses response-path-route-object;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping path-computation {
|
||||
description
|
||||
"Reusable grouping that defined data for requests or for
|
||||
responses of a path-computation";
|
||||
container services {
|
||||
description
|
||||
"Definition of path-computation requests.";
|
||||
uses service;
|
||||
}
|
||||
|
||||
container responses {
|
||||
description
|
||||
"Definition of path-computation responses.";
|
||||
uses response;
|
||||
}
|
||||
}
|
||||
|
||||
container services {
|
||||
description
|
||||
"Definition of path-computation requests.";
|
||||
uses service;
|
||||
}
|
||||
|
||||
container responses {
|
||||
description
|
||||
"Definition of path-computation responses.";
|
||||
uses response;
|
||||
}
|
||||
|
||||
augment "/gapi:api" {
|
||||
description "Add the gnpy-path-computation imput in the API request.";
|
||||
uses path-computation;
|
||||
}
|
||||
}
|
||||
35
gnpy/yang/gnpy-sim-params@2025-04-10.tree
Normal file
35
gnpy/yang/gnpy-sim-params@2025-04-10.tree
Normal file
@@ -0,0 +1,35 @@
|
||||
module: gnpy-sim-params
|
||||
+--rw sim-params
|
||||
+--rw raman_params
|
||||
| +--rw flag? boolean
|
||||
| +--rw order? uint16
|
||||
| +--rw method? identityref
|
||||
| +--rw result_spatial_resolution? decimal64
|
||||
| +--rw solver_spatial_resolution? decimal64
|
||||
+--rw nli_params
|
||||
+--rw method? identityref
|
||||
+--rw dispersion_tolerance? decimal64
|
||||
+--rw phase_shift_tolerance? decimal64
|
||||
+--rw (computation)?
|
||||
+--:(explicit-channels)
|
||||
| +--rw computed_channels* uint16
|
||||
+--:(nb_of_channels)
|
||||
+--rw computed_number_of_channels? uint16
|
||||
|
||||
augment /gapi:api:
|
||||
+--rw sim-params
|
||||
+--rw raman_params
|
||||
| +--rw flag? boolean
|
||||
| +--rw order? uint16
|
||||
| +--rw method? identityref
|
||||
| +--rw result_spatial_resolution? decimal64
|
||||
| +--rw solver_spatial_resolution? decimal64
|
||||
+--rw nli_params
|
||||
+--rw method? identityref
|
||||
+--rw dispersion_tolerance? decimal64
|
||||
+--rw phase_shift_tolerance? decimal64
|
||||
+--rw (computation)?
|
||||
+--:(explicit-channels)
|
||||
| +--rw computed_channels* uint16
|
||||
+--:(nb_of_channels)
|
||||
+--rw computed_number_of_channels? uint16
|
||||
176
gnpy/yang/gnpy-sim-params@2025-04-10.yang
Normal file
176
gnpy/yang/gnpy-sim-params@2025-04-10.yang
Normal file
@@ -0,0 +1,176 @@
|
||||
module gnpy-sim-params {
|
||||
yang-version 1.1;
|
||||
namespace "urn:gnpy-sim-params";
|
||||
|
||||
prefix sim-params;
|
||||
|
||||
import gnpy-api {
|
||||
prefix "gapi";
|
||||
revision-date 2025-06-13;
|
||||
}
|
||||
|
||||
organization
|
||||
"Telecom Infra Project OOPT PSE Working Group";
|
||||
contact
|
||||
"WG Web: <https://github.com/Telecominfraproject/oopt-gnpy>
|
||||
contact: <mailto:esther.lerouzic@orange.com>
|
||||
";
|
||||
description
|
||||
"YANG model for gnpy network input for path computation simulation params- 2025";
|
||||
|
||||
revision 2025-04-10 {
|
||||
description
|
||||
"First yang model for sim-params option";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
|
||||
identity nli-method {
|
||||
description "Base identity for NLI calculation methods";
|
||||
}
|
||||
|
||||
identity ggn_spectrally_separated {
|
||||
base nli-method;
|
||||
description "GGN spectrally separated method";
|
||||
}
|
||||
|
||||
identity ggn_approx {
|
||||
base nli-method;
|
||||
description "GGN approximation method";
|
||||
}
|
||||
|
||||
identity gn_model_analytic {
|
||||
base nli-method;
|
||||
description "GN model analytic method";
|
||||
}
|
||||
|
||||
identity raman-method {
|
||||
description "Base identity for Raman calculation methods";
|
||||
}
|
||||
|
||||
identity perturbative {
|
||||
base raman-method;
|
||||
description "Raman perturbative method";
|
||||
}
|
||||
|
||||
identity numerical {
|
||||
base raman-method;
|
||||
description "Raman numerical first order method";
|
||||
}
|
||||
|
||||
grouping raman-sim-params {
|
||||
description
|
||||
"Raman simulation attributes";
|
||||
container raman_params {
|
||||
description
|
||||
"Simulation parameters definition for Raman effect evaluation.";
|
||||
leaf flag {
|
||||
type boolean;
|
||||
description
|
||||
"boolean for enabling/disable the evaluation of the Raman power
|
||||
profile in frequency and position
|
||||
";
|
||||
}
|
||||
leaf order {
|
||||
type uint16;
|
||||
default 2;
|
||||
description
|
||||
"Solution order for perturbative method";
|
||||
}
|
||||
leaf method {
|
||||
type identityref {
|
||||
base raman-method;
|
||||
}
|
||||
description
|
||||
"Method used for Raman effect evaluation.";
|
||||
}
|
||||
leaf result_spatial_resolution {
|
||||
type decimal64 {
|
||||
fraction-digits 3;
|
||||
}
|
||||
description
|
||||
"Spatial resolution of the evaluated Raman power profile in m. Suggested value is 10e3m";
|
||||
}
|
||||
leaf solver_spatial_resolution {
|
||||
type decimal64 {
|
||||
fraction-digits 3;
|
||||
}
|
||||
description
|
||||
"Spatial step for the iterative solution of the first order ode. a suggested value is 10e3 m";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping nli-sim-params {
|
||||
description
|
||||
"NLI simulation attributes";
|
||||
container nli_params {
|
||||
description
|
||||
"Simulation parameters definition for Non Linear
|
||||
Interference (NLI) effect evaluation.";
|
||||
leaf method {
|
||||
type identityref {
|
||||
base nli-method;
|
||||
}
|
||||
description "Model used for the NLI evaluation.";
|
||||
}
|
||||
leaf dispersion_tolerance {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
default "1.0";
|
||||
description "Tuning parameter for ggn model solution";
|
||||
}
|
||||
leaf phase_shift_tolerance {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
default "0.1";
|
||||
description "Tuning parameter for ggn model solution";
|
||||
}
|
||||
|
||||
choice computation {
|
||||
description
|
||||
"Definition of the channels on which the NLI is evaluated: explicir position or amount.";
|
||||
case explicit-channels {
|
||||
leaf-list computed_channels {
|
||||
type uint16 {
|
||||
range "1..max";
|
||||
}
|
||||
ordered-by user;
|
||||
description "The exact channel indices (starting from 1) on which the NLI is evaluated";
|
||||
}
|
||||
}
|
||||
case nb_of_channels {
|
||||
leaf computed_number_of_channels {
|
||||
type uint16;
|
||||
description "The number of channels on which the NLI is evaluated";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping sim-params {
|
||||
description
|
||||
"Simulation parameters definition.";
|
||||
container sim-params {
|
||||
description
|
||||
"Simulation parameters definition.";
|
||||
uses raman-sim-params;
|
||||
uses nli-sim-params;
|
||||
}
|
||||
}
|
||||
|
||||
container sim-params {
|
||||
description
|
||||
"Simulation parameters definition.";
|
||||
uses raman-sim-params;
|
||||
uses nli-sim-params;
|
||||
}
|
||||
|
||||
augment "/gapi:api" {
|
||||
description "Add the gnpy-sim-params input in the API request.";
|
||||
uses sim-params;
|
||||
}
|
||||
}
|
||||
23
gnpy/yang/gnpy-spectrum@2025-04-10.tree
Normal file
23
gnpy/yang/gnpy-spectrum@2025-04-10.tree
Normal file
@@ -0,0 +1,23 @@
|
||||
module: gnpy-spectrum
|
||||
+--rw spectrum* [f_min]
|
||||
+--rw f_min decimal64
|
||||
+--rw f_max decimal64
|
||||
+--rw slot_width decimal64
|
||||
+--rw delta_pdb? decimal64
|
||||
+--rw baud_rate? decimal64
|
||||
+--rw tx_osnr? decimal64
|
||||
+--rw roll_off? union
|
||||
+--rw tx_power_dbm? decimal64
|
||||
+--rw label? string
|
||||
|
||||
augment /gapi:api:
|
||||
+--rw spectrum* [f_min]
|
||||
+--rw f_min decimal64
|
||||
+--rw f_max decimal64
|
||||
+--rw slot_width decimal64
|
||||
+--rw delta_pdb? decimal64
|
||||
+--rw baud_rate? decimal64
|
||||
+--rw tx_osnr? decimal64
|
||||
+--rw roll_off? union
|
||||
+--rw tx_power_dbm? decimal64
|
||||
+--rw label? string
|
||||
105
gnpy/yang/gnpy-spectrum@2025-04-10.yang
Normal file
105
gnpy/yang/gnpy-spectrum@2025-04-10.yang
Normal file
@@ -0,0 +1,105 @@
|
||||
module gnpy-spectrum {
|
||||
yang-version 1.1;
|
||||
namespace "urn:gnpy-spectrum";
|
||||
|
||||
prefix spectrum;
|
||||
|
||||
import gnpy-api {
|
||||
prefix "gapi";
|
||||
revision-date 2025-06-13;
|
||||
}
|
||||
|
||||
import gnpy-eqpt-config {
|
||||
prefix "geqpt";
|
||||
revision-date 2025-05-26;
|
||||
}
|
||||
|
||||
organization
|
||||
"Telecom Infra Project OOPT PSE Working Group";
|
||||
contact
|
||||
"WG Web: <https://github.com/Telecominfraproject/oopt-gnpy>
|
||||
contact: <mailto:esther.lerouzic@orange.com>
|
||||
";
|
||||
description
|
||||
"YANG model for gnpy network input for path computation simulation params- 2025";
|
||||
|
||||
revision 2025-04-10 {
|
||||
description
|
||||
"First yang model for spectrum option";
|
||||
reference
|
||||
"YANG model for network input for path computation with gnpy";
|
||||
}
|
||||
|
||||
grouping spectrum-grouping {
|
||||
description
|
||||
"Attributes of a spectrum partition.";
|
||||
leaf f_min {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"Partition definition: f_min is the first carrier central frequency
|
||||
f_max is the last one. partitions must not overlap.
|
||||
Note that the meaning of f_min and f_max is different than the one
|
||||
in equipment_config SpectralInformation";
|
||||
}
|
||||
leaf f_max {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
must ". >= ./../f_min";
|
||||
mandatory true;
|
||||
description
|
||||
"Partition definition: f_min is the first carrier central frequency
|
||||
f_max is the last one. partitions must not overlap.
|
||||
Note that the meaning of f_min and f_max is different than the one
|
||||
in equipment_config SpectralInformation";
|
||||
}
|
||||
leaf slot_width {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
mandatory true;
|
||||
description "Carrier spectrum occupation. Carriers of this partition
|
||||
are spaced at slot_width offsets.";
|
||||
}
|
||||
leaf delta_pdb {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
description "Power offset compared to the reference power used for design
|
||||
(SI block in equipment library) to be applied by ROADM to equalize the
|
||||
carriers in this partition. Default value is 0 dB.";
|
||||
}
|
||||
uses geqpt:SI-Transceiver;
|
||||
leaf label {
|
||||
type string;
|
||||
description
|
||||
"Unique label that identifies the spectrum partition.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping spectrum {
|
||||
description
|
||||
"Definition of the spectrum to propagate.";
|
||||
list spectrum {
|
||||
description
|
||||
"List of spectrum partitions.";
|
||||
key f_min;
|
||||
uses spectrum-grouping;
|
||||
}
|
||||
}
|
||||
|
||||
list spectrum {
|
||||
description
|
||||
"List of spectrum partitions.";
|
||||
key f_min;
|
||||
uses spectrum-grouping;
|
||||
}
|
||||
|
||||
augment "/gapi:api" {
|
||||
description "Add the gnpy-spectrum input in the API request.";
|
||||
uses spectrum;
|
||||
}
|
||||
}
|
||||
293
gnpy/yang/precision_dict.py
Normal file
293
gnpy/yang/precision_dict.py
Normal file
@@ -0,0 +1,293 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# precision of fraction digits collected in yang models
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
PRECISION_DICT = {
|
||||
"contact": -1, "date": -1, "description": -1, "module": -1, "organization": -1,
|
||||
"f_min": 1,
|
||||
"f_max": 1,
|
||||
"length": 6,
|
||||
"loss_coef": 6,
|
||||
"pmd_coef": 18,
|
||||
"frequency": 1,
|
||||
"freq": 2, "ref_frequency": 1, "ref_wavelength": 12,
|
||||
"g0": 14, "loss_coef_value": 16, "position": 6, "reference_frequency": 1,
|
||||
"att_in": 2,
|
||||
"con_in": 2,
|
||||
"con_out": 2,
|
||||
"temperature": 2,
|
||||
"power": 9,
|
||||
"gain_target": 6,
|
||||
"tilt_target": 6,
|
||||
"out_voa": 2,
|
||||
"in_voa": 2,
|
||||
"delta_p": 6,
|
||||
"spacing": 2,
|
||||
"target_pch_out_db": 2,
|
||||
"target_psd_out_mWperGHz": 10,
|
||||
"target_out_mWperSlotWidth": 10,
|
||||
"per_degree_pch_out_db": 2,
|
||||
"per_degree_psd_out_mWperGHz": 10,
|
||||
"per_degree_psd_out_mWperSlotWidth": 10,
|
||||
"number-of-channels": 0,
|
||||
"loss": 2,
|
||||
"city": -1,
|
||||
"region": -1,
|
||||
"latitude": 6,
|
||||
"longitude": 6,
|
||||
"length_units": -1,
|
||||
"propagation_direction": -1,
|
||||
"type_variety": -1,
|
||||
"degree_uid": -1,
|
||||
"preamp_variety_list": -1,
|
||||
"booster_variety_list": -1,
|
||||
"from_degree": -1,
|
||||
"to_degree": -1,
|
||||
"impairment_id": 0,
|
||||
"variety_list": -1,
|
||||
"uid": -1,
|
||||
"type": -1,
|
||||
"from_node": -1,
|
||||
"to_node": -1,
|
||||
"network_name": -1,
|
||||
"output-power": 8,
|
||||
"tx_power": 5,
|
||||
"path_bandwidth": 1,
|
||||
"accumulative-value": 8,
|
||||
"N": 0,
|
||||
"M": 0,
|
||||
"trx_mode": -1,
|
||||
"max-nb-of-channel": 0,
|
||||
"technology": -1,
|
||||
"trx_type": -1,
|
||||
"transponder-type": -1,
|
||||
"transponder-mode": -1,
|
||||
"explicit-route-usage": -1,
|
||||
"disjointness": -1,
|
||||
"index": 0,
|
||||
"node-id": -1,
|
||||
"link-tp-id": -1,
|
||||
"hop-type": -1,
|
||||
"source": -1,
|
||||
"destination": -1,
|
||||
"src-tp-id": -1,
|
||||
"dst-tp-id": -1,
|
||||
"synchronization-id": -1,
|
||||
"relaxable": -1,
|
||||
"request-id-number": -1,
|
||||
"request-id": -1,
|
||||
"bidirectional": -1,
|
||||
"metric-type": -1,
|
||||
"response-id": -1,
|
||||
"no-path": -1,
|
||||
"result_spatial_resolution": 3,
|
||||
"solver_spatial_resolution": 3,
|
||||
"dispersion_tolerance": 1,
|
||||
"phase_shift_tolerance": 1,
|
||||
"flag": -1,
|
||||
"order": 0,
|
||||
"method": -1,
|
||||
"computed_channels": 0,
|
||||
"computed_number_of_channels": 0,
|
||||
"nf_min": 2,
|
||||
"nf_max": 2,
|
||||
"nf0": 2,
|
||||
"nf_coef": 10,
|
||||
"coef_order": 0,
|
||||
"gain_flatmax": 2,
|
||||
"gain_min": 2,
|
||||
"extended_gain_range": 2,
|
||||
"p_max": 2,
|
||||
"dispersion": 8,
|
||||
'dispersion_slope': 11,
|
||||
"gamma": 8,
|
||||
"effective_area": 14,
|
||||
"min_value": 2,
|
||||
"max_value": 2,
|
||||
"step": 2,
|
||||
"lower-frequency": 2,
|
||||
"upper-frequency": 2,
|
||||
"cr": 9,
|
||||
"frequency_offset": 2,
|
||||
"max_length": 2,
|
||||
"max_loss": 2,
|
||||
"max_fiber_lineic_loss_for_raman": 2,
|
||||
"target_extended_gain": 2,
|
||||
"padding": 2,
|
||||
"EOL": 2,
|
||||
"span_loss_ref": 2,
|
||||
"power_slope": 2,
|
||||
"voa_margin": 2,
|
||||
"voa_step": 2,
|
||||
"add_drop_osnr": 2,
|
||||
"pmd": 15,
|
||||
"pdl": 2,
|
||||
"baud_rate": 2,
|
||||
"power_dbm": 2,
|
||||
"roll_off": 2,
|
||||
"tx_osnr": 2,
|
||||
"tx_power_dbm": 2,
|
||||
"sys_margins": 2,
|
||||
"min": 2,
|
||||
"max": 2,
|
||||
"OSNR": 2,
|
||||
"min_spacing": 2,
|
||||
"bit_rate": 2,
|
||||
"cost": 2,
|
||||
"chromatic_dispersion": 2,
|
||||
"penalty_value": 2,
|
||||
"equalization_offset_db": 4,
|
||||
"preamp_variety": -1,
|
||||
"booster_variety": -1,
|
||||
"amplifiers": -1,
|
||||
"advanced_config_from_json": -1,
|
||||
"default_config_from_json": -1,
|
||||
"allowed_for_design": -1,
|
||||
"type_def": -1,
|
||||
"raman": -1,
|
||||
"out_voa_auto": -1,
|
||||
"in_voa_auto": -1,
|
||||
"other_name": -1,
|
||||
"power_mode": -1,
|
||||
"roadm-path-impairments-id": 0,
|
||||
"use_si_channel_count_for_design": -1,
|
||||
"comment": -1,
|
||||
"format": -1,
|
||||
"roadm-osnr": 2,
|
||||
"nf_ripple": 18,
|
||||
"dgt": 18,
|
||||
"gain_ripple": 18,
|
||||
"slot_width": 2,
|
||||
"delta_pdb": 2,
|
||||
"label": -1,
|
||||
"roadm-pmd": 8,
|
||||
"otsi-carrier-frequency": 9,
|
||||
"oms-element-uid": -1,
|
||||
"configured-mode": -1,
|
||||
"type-variety": -1,
|
||||
"frequency-range-id": 0,
|
||||
"stage-order": 0,
|
||||
"name": -1,
|
||||
"nominal-carrier-power": 2,
|
||||
"nominal-psd": 16,
|
||||
"actual-gain": 2,
|
||||
"in-voa": 2,
|
||||
"out-voa": 2,
|
||||
"tilt-target": 2,
|
||||
"total-output-power": 2,
|
||||
"raman-direction": -1,
|
||||
"pump-id": 0,
|
||||
"delta-power": 2,
|
||||
"loss-coef": 2,
|
||||
"total-loss": 2,
|
||||
"conn-in": 2,
|
||||
"conn-out": 2,
|
||||
"roadm-cd": 5,
|
||||
"roadm-pdl": 2,
|
||||
"roadm-inband-crosstalk": 2,
|
||||
"roadm-maxloss": 2,
|
||||
"roadm-pmax": 2,
|
||||
"roadm-noise-figure": 5,
|
||||
"roadm-minloss": 2,
|
||||
"roadm-typloss": 2,
|
||||
"roadm-pmin": 2,
|
||||
"roadm-ptyp": 2,
|
||||
"generalized-snr": 2,
|
||||
"equalization-mode": -1,
|
||||
"otsi-carrier-id": 0,
|
||||
"e2e-mc-path-id": 0,
|
||||
"otsi-group-ref": -1,
|
||||
"media-channel-id": 0,
|
||||
"otsi-carrier-ref": -1,
|
||||
"e2e-mc-path-ref": -1,
|
||||
"elt-index": 0,
|
||||
"link-ref": -1,
|
||||
"oms-element-ref": -1,
|
||||
"otsi-ref": -1,
|
||||
"otsi-group-id": -1,
|
||||
"explicit-transceiver-mode-id": -1,
|
||||
"transponder-id": 0,
|
||||
"termination-type-capabilities": -1,
|
||||
"transceiver-id": 0,
|
||||
"explicit-transceiver-mode-ref": -1,
|
||||
"configured-termination-type": -1,
|
||||
"group-id": 0,
|
||||
"regen-metric": 0,
|
||||
"transponder-ref": -1,
|
||||
"transceiver-ref": -1,
|
||||
"protection-type": -1,
|
||||
"inter-layer-sequence-number": 0,
|
||||
"roadm-path-impairments": -1,
|
||||
"ltp-ref": -1,
|
||||
"add-path-impairments": -1,
|
||||
"drop-path-impairments": -1,
|
||||
"ttp-transponder-ref": -1,
|
||||
"ttp-transceiver-ref": -1,
|
||||
"is-allowed": -1,
|
||||
"penalty-value": 2,
|
||||
"max-chromatic-dispersion": 2,
|
||||
"cd-value": 2,
|
||||
"max-polarization-mode-dispersion": 2,
|
||||
"pmd-value": 2,
|
||||
"available-baud-rate": 1,
|
||||
"roll-off": 4,
|
||||
"fec-code-rate": 8,
|
||||
"fec-threshold": 8,
|
||||
"polarization-skew": 2,
|
||||
"dwdm-n": -1,
|
||||
"cwdm-n": -1,
|
||||
"wson-dwdm-channel-spacing": -1,
|
||||
"wson-cwdm-channel-spacing": -1,
|
||||
"subcarrier-dwdm-n": 0,
|
||||
"slot-width-granularity": -1,
|
||||
"min-slot-width-factor": 0,
|
||||
"max-slot-width-factor": 0,
|
||||
"grid-type": -1,
|
||||
"priority": 0,
|
||||
"flexi-n": 0,
|
||||
"flexi-m": 0,
|
||||
"flexi-grid-channel-spacing": -1,
|
||||
"flexi-ncfg": -1,
|
||||
"flexi-n-step": 0,
|
||||
"mode-id": -1,
|
||||
"supported-application-codes": -1,
|
||||
"supported-organizational-modes": -1,
|
||||
"standard-mode": -1,
|
||||
"operational-mode": -1,
|
||||
"organization-identifier": -1,
|
||||
"line-coding-bitrate": -1,
|
||||
"bitrate": 0,
|
||||
"max-diff-group-delay": 2,
|
||||
"max-polarization-dependant-loss": 2,
|
||||
"pdl-value": 2,
|
||||
"available-modulation-type": -1,
|
||||
"min-OSNR": 2,
|
||||
"rx-ref-channel-power": 2,
|
||||
"rx-channel-power-value": 2,
|
||||
"min-Q-factor": 2,
|
||||
"min-carrier-spacing": 6,
|
||||
"available-fec-type": -1,
|
||||
"in-band-osnr": 2,
|
||||
"out-of-band-osnr": 2,
|
||||
"tx-polarization-power-difference": 2,
|
||||
"min-central-frequency": 9,
|
||||
"max-central-frequency": 9,
|
||||
"transceiver-tunability": 6,
|
||||
"tx-channel-power-min": 2,
|
||||
"tx-channel-power-max": 2,
|
||||
"rx-channel-power-min": 2,
|
||||
"rx-channel-power-max": 2,
|
||||
"rx-total-power-max": 2,
|
||||
"tx-channel-power": 2,
|
||||
"rx-channel-power": 2,
|
||||
"rx-total-power": 2,
|
||||
"wavelength-assignment": -1,
|
||||
"gsnr-extra-margin": 2,
|
||||
"estimated-gsnr": 2,
|
||||
"estimated-eol-gsnr": 2,
|
||||
"estimated-lowest-gsnr": 2
|
||||
}
|
||||
61
gnpy/yang/yang-library-gnpy.json
Normal file
61
gnpy/yang/yang-library-gnpy.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"ietf-yang-library:modules-state": {
|
||||
"module-set-id": "gnpy-library",
|
||||
"module": [
|
||||
{
|
||||
"name": "gnpy-network-topology",
|
||||
"namespace": "gnpy:gnpy-network-topology",
|
||||
"revision": "2025-03-01",
|
||||
"conformance-type": "implement"
|
||||
},
|
||||
{
|
||||
"name": "gnpy-path-computation",
|
||||
"namespace": "gnpy:gnpy-path-computation",
|
||||
"revision": "2025-01-20",
|
||||
"conformance-type": "implement"
|
||||
},
|
||||
{
|
||||
"name": "gnpy-sim-params",
|
||||
"namespace": "gnpy:gnpy-sim-params",
|
||||
"revision": "2025-04-10",
|
||||
"conformance-type": "implement"
|
||||
},
|
||||
{
|
||||
"name": "gnpy-eqpt-config",
|
||||
"namespace": "gnpy:gnpy-eqpt",
|
||||
"revision": "2025-05-26",
|
||||
"conformance-type": "implement"
|
||||
},
|
||||
{
|
||||
"name": "gnpy-edfa-config",
|
||||
"namespace": "gnpy:gnpy-edfa-config",
|
||||
"revision": "2025-04-10",
|
||||
"conformance-type": "implement"
|
||||
},
|
||||
{
|
||||
"name": "gnpy-sim-params",
|
||||
"namespace": "gnpy:gnpy-sim-params",
|
||||
"revision": "2025-04-10",
|
||||
"conformance-type": "implement"
|
||||
},
|
||||
{
|
||||
"name": "gnpy-spectrum",
|
||||
"namespace": "gnpy:gnpy-spectrum",
|
||||
"revision": "2025-04-10",
|
||||
"conformance-type": "implement"
|
||||
},
|
||||
{
|
||||
"name": "ietf-optical-impairment-topology",
|
||||
"namespace": "urn:ietf:params:xml:ns:yang:ietf-optical-impairment-topology",
|
||||
"revision": "2024-05-21",
|
||||
"conformance-type": "implement"
|
||||
},
|
||||
{
|
||||
"name": "ietf-layer0-types",
|
||||
"namespace": "urn:ietf:params:xml:ns:yang:ietf-layer0-types",
|
||||
"revision": "2024-03-04",
|
||||
"conformance-type": "implement"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,559 +0,0 @@
|
||||
*********************************************
|
||||
Equipment and Network description definitions
|
||||
*********************************************
|
||||
|
||||
1. Equipment description
|
||||
########################
|
||||
|
||||
Equipment description defines equipment types and those parameters.
|
||||
Description is made in JSON file with predefined structure. By default
|
||||
**gnpy-transmission-example** uses **eqpt_config.json** file and that
|
||||
can be changed with **-e** or **--equipment** command line parameter.
|
||||
Parsing of JSON file is made with
|
||||
**gnpy.core.equipment.load_equipment(equipment_description)** and return
|
||||
value is a dictionary of format **dict[‘equipment
|
||||
type’][‘subtype’]=object**
|
||||
|
||||
1.1. Structure definition
|
||||
*************************
|
||||
|
||||
1.1.1. Equipment types
|
||||
*************************
|
||||
|
||||
Every equipment type is defined in JSON root with according name and
|
||||
array of parameters as value.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
{"Edfa": [...],
|
||||
"Fiber": [...]
|
||||
}
|
||||
|
||||
|
||||
1.1.2. Equipment parameters and subtypes
|
||||
*****************************************
|
||||
|
||||
|
||||
Array of parameters is a list of objects with unordered parameter name
|
||||
and its value definition. In case of multiple equipment subtypes each
|
||||
object contains **"type_variety":”type name”** name:value combination,
|
||||
if only one subtype exists **"type_variety"** name is not mandatory and
|
||||
it will be marked with **”default”** value.
|
||||
|
||||
.. 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
|
||||
}
|
||||
],
|
||||
"Fiber": [{
|
||||
"type_variety": "SSMF",
|
||||
"dispersion": 1.67e-05,
|
||||
"gamma": 0.00127
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
1.2. Equipment parameters by type
|
||||
*********************************
|
||||
|
||||
1.2.1. EDFA element
|
||||
*******************
|
||||
|
||||
Four types of EDFA definition are possible. Description JSON file
|
||||
location is in **gnpy-transmission-example** folder:
|
||||
|
||||
- Advanced – with JSON file describing gain/noise figure tilt and
|
||||
gain/noise figure ripple. **"advanced_config_from_json"** value
|
||||
contains filename.
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"Edfa":[{
|
||||
"type_variety": "high_detail_model_example",
|
||||
"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 – 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_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 – 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": "openroadm_ila_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
|
||||
********************
|
||||
|
||||
Fiber element with its parameters:
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"Fiber":[{
|
||||
"type_variety": "SSMF",
|
||||
"dispersion": 1.67e-05,
|
||||
"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
|
||||
********************
|
||||
|
||||
Spans element with its parameters:
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"Spans":[{
|
||||
"power_mode":true,
|
||||
"delta_power_range_db": [0,0,0.5],
|
||||
"max_length": 150,
|
||||
"length_units": "km",
|
||||
"max_loss": 28,
|
||||
"padding": 10,
|
||||
"EOL": 0,
|
||||
"con_in": 0,
|
||||
"con_out": 0
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
1.2.4. Spectral Information
|
||||
***************************
|
||||
|
||||
Spectral information with its parameters:
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"SI":[{
|
||||
"f_min": 191.3e12,
|
||||
"baud_rate": 32e9,
|
||||
"f_max":195.1e12,
|
||||
"spacing": 50e9,
|
||||
"power_dbm": 0,
|
||||
"power_range_db": [0,0,0.5],
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"sys_margins": 0
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
1.2.5. Transceiver element
|
||||
**************************
|
||||
|
||||
Transceiver element with its parameters. **”mode”** can contain multiple
|
||||
Transceiver operation formats.
|
||||
|
||||
Note that ``OSNR`` parameter refers to the receiver's minimal OSNR threshold for a given mode.
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"Transceiver":[{
|
||||
"frequency":{
|
||||
"min": 191.35e12,
|
||||
"max": 196.1e12
|
||||
},
|
||||
"mode":[
|
||||
{
|
||||
"format": "mode 1",
|
||||
"baud_rate": 32e9,
|
||||
"OSNR": 11,
|
||||
"bit_rate": 100e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost":1
|
||||
},
|
||||
{
|
||||
"format": "mode 2",
|
||||
"baud_rate": 66e9,
|
||||
"OSNR": 15,
|
||||
"bit_rate": 200e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost":1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
***********************
|
||||
2. Network description
|
||||
***********************
|
||||
|
||||
Network description defines network elements with additional to
|
||||
equipment description parameters, metadata and elements interconnection.
|
||||
Description is made in JSON file with predefined structure. By default
|
||||
**gnpy-transmission-example** uses **edfa_example_network.json** file
|
||||
and can be changed from command line. Parsing of JSON file is made with
|
||||
**gnpy.core.network.load_network(network_description,
|
||||
equipment_description)** and return value is **DiGraph** object which
|
||||
mimics network description.
|
||||
|
||||
2.1. Structure definition
|
||||
##########################
|
||||
|
||||
2.1.1. File root structure
|
||||
***************************
|
||||
|
||||
Network description JSON file root consist of three unordered parts:
|
||||
|
||||
- network_name – name of described network or service, is not used as
|
||||
of now
|
||||
|
||||
- elements - contains array of network element objects with their
|
||||
respective parameters
|
||||
|
||||
- connections – contains array of unidirectional connection objects
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
{"network_name": "Example Network",
|
||||
"elements": [{...},
|
||||
{...}
|
||||
],
|
||||
"connections": [{...},
|
||||
{...}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
2.1.2. Elements parameters and subtypes
|
||||
****************************************
|
||||
|
||||
Array of network element objects consist of unordered parameter names
|
||||
and those values. In case of **"type_variety"** absence
|
||||
**"type_variety":”default”** name:value combination is used. As of the
|
||||
moment, existence of used **"type_variety"** in equipment description is
|
||||
obligatory.
|
||||
|
||||
2.2. Element parameters by type
|
||||
*********************************
|
||||
|
||||
2.2.1. Transceiver element
|
||||
***************************
|
||||
|
||||
Transceiver element with its parameters.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{"uid": "trx Site_A",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site_A",
|
||||
"region": "",
|
||||
"latitude": 0,
|
||||
"longitude": 0
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
}
|
||||
|
||||
|
||||
|
||||
2.2.2. ROADM element
|
||||
*********************
|
||||
|
||||
ROADM element with its parameters. **“params”** is optional, if not used
|
||||
default loss value of 20dB is used.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{"uid": "roadm Site_A",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site_A",
|
||||
"region": "",
|
||||
"latitude": 0,
|
||||
"longitude": 0
|
||||
}
|
||||
},
|
||||
"type": "Roadm",
|
||||
"params": {
|
||||
"loss": 17
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2.2.3. Fused element
|
||||
*********************
|
||||
|
||||
Fused element with its parameters. **“params”** is optional, if not used
|
||||
default loss value of 1dB is used.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{"uid": "ingress fused spans in Site_B",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site_B",
|
||||
"region": "",
|
||||
"latitude": 0,
|
||||
"longitude": 0
|
||||
}
|
||||
},
|
||||
"type": "Fused",
|
||||
"params": {
|
||||
"loss": 0.5
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2.2.4. Fiber element
|
||||
*********************
|
||||
|
||||
Fiber element with its parameters.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{"uid": "fiber (Site_A \\u2192 Site_B)",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "",
|
||||
"region": "",
|
||||
"latitude": 0.0,
|
||||
"longitude": 0.0
|
||||
}
|
||||
},
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"length": 40.0,
|
||||
"length_units": "km",
|
||||
"loss_coef": 0.2
|
||||
}
|
||||
}
|
||||
|
||||
2.2.5. RamanFiber 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.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{"uid": "Edfa1",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 16,
|
||||
"tilt_target": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site_A",
|
||||
"region": "",
|
||||
"latitude": 2,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2.3. Connections objects
|
||||
*************************
|
||||
|
||||
Each unidirectional connection object in connections array consist of
|
||||
two unordered **”from_node”** and **”to_node”** name pair with values
|
||||
corresponding to element **”uid”**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{"from_node": "roadm 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_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_tolerance": 0.1,
|
||||
"computed_channels": [1, 18, 37, 56, 75]
|
||||
}
|
||||
}
|
||||
10
setup.cfg
10
setup.cfg
@@ -49,6 +49,7 @@ console_scripts =
|
||||
gnpy-transmission-example = gnpy.tools.cli_examples:transmission_main_example
|
||||
gnpy-path-request = gnpy.tools.cli_examples:path_requests_run
|
||||
gnpy-convert-xls = gnpy.tools.convert:_do_convert
|
||||
gnpy-convert-yang = gnpy.tools.convert_legacy_yang:main
|
||||
|
||||
[options]
|
||||
install_requires =
|
||||
@@ -58,11 +59,13 @@ install_requires =
|
||||
networkx>=3.1,<4
|
||||
# numpy 1.25 removed support for Python 3.8
|
||||
numpy>=1.24.4,<2
|
||||
oopt_gnpy_libyang>=0.0.14
|
||||
openpyxl>=3.1.5,<4
|
||||
pbr>=6.0.0,<7
|
||||
# scipy 1.11 removed support for Python 3.8
|
||||
scipy>=1.10.1,<2
|
||||
# xlrd 2.x removed support for .xlsx, it's only .xls now
|
||||
xlrd>=1.2.0,<2
|
||||
xlrd>=2.0.1,<3
|
||||
|
||||
[options.extras_require]
|
||||
tests =
|
||||
@@ -76,8 +79,9 @@ tests =
|
||||
docs =
|
||||
alabaster>=0.7.12,<1
|
||||
docutils>=0.17.1,<1
|
||||
myst-parser>=0.16.1,<1
|
||||
myst-parser>=4.0.1,<5
|
||||
Pygments>=2.11.2,<3
|
||||
rstcheck
|
||||
Sphinx>=5.3.0,<6
|
||||
Sphinx>=8.1.3,<9
|
||||
sphinxcontrib-bibtex>=2.4.1,<3
|
||||
sphinx_rtd_theme>=3.0.2,<4
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
# Copyright (C) 2020 Telecom Infra Project and GNPy contributors
|
||||
# see LICENSE.md for a list of contributors
|
||||
#
|
||||
# test_amplifier
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
import pytest
|
||||
from gnpy.core.parameters import SimParams, NLIParams, RamanParams
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
3820
tests/data/convert/GNPy_api_example.json
Normal file
3820
tests/data/convert/GNPy_api_example.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"network_name": "EDFA Example Network - P2P",
|
||||
"elements": [
|
||||
{
|
||||
"uid": "Site_A",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site A",
|
||||
"region": "",
|
||||
"latitude": 0.0,
|
||||
"longitude": 0.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"length": 80.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0.0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5,
|
||||
"pmd_coef": 3.0e-15
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": 1.0,
|
||||
"longitude": 0.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Edfa1",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 17.0,
|
||||
"tilt_target": 0.0,
|
||||
"out_voa": 0.0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": 2.0,
|
||||
"longitude": 0.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Site_B",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site B",
|
||||
"region": "",
|
||||
"latitude": 2.0,
|
||||
"longitude": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"from_node": "Site_A",
|
||||
"to_node": "Span1"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1",
|
||||
"to_node": "Edfa1"
|
||||
},
|
||||
{
|
||||
"from_node": "Edfa1",
|
||||
"to_node": "Site_B"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
318
tests/data/convert/GNPy_yang_formatted-edfa-config_expected.json
Normal file
318
tests/data/convert/GNPy_yang_formatted-edfa-config_expected.json
Normal file
@@ -0,0 +1,318 @@
|
||||
{
|
||||
"gnpy-edfa-config:edfa-config": {
|
||||
"f_min": "191275000000000.0",
|
||||
"f_max": "196125000000000.0",
|
||||
"nf_fit_coeff": [
|
||||
{
|
||||
"coef_order": 0,
|
||||
"nf_coef": "0.000168241"
|
||||
},
|
||||
{
|
||||
"coef_order": 1,
|
||||
"nf_coef": "0.0469961"
|
||||
},
|
||||
{
|
||||
"coef_order": 2,
|
||||
"nf_coef": "0.0359549"
|
||||
},
|
||||
{
|
||||
"coef_order": 3,
|
||||
"nf_coef": "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.0024172385953583",
|
||||
"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",
|
||||
"-0.000096221623730266",
|
||||
"-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"
|
||||
],
|
||||
"gain_ripple": [
|
||||
"0.1359703369791596",
|
||||
"0.11822862697916037",
|
||||
"0.09542181697916163",
|
||||
"0.06245819697916133",
|
||||
"0.02602813697916062",
|
||||
"-0.003619983020840322",
|
||||
"-0.018326963020840026",
|
||||
"-0.0246928330208398",
|
||||
"-0.016792253020838643",
|
||||
"-0.002813863020840301",
|
||||
"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.004043586979161517",
|
||||
"0.000710466979160884",
|
||||
"-0.001576313020837716",
|
||||
"-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.002172653020839021",
|
||||
"0.01393231697916164",
|
||||
"0.028098946979159933",
|
||||
"0.040326236979161934",
|
||||
"0.05257029697916238",
|
||||
"0.06479749697916048",
|
||||
"0.07704745697916238"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"gnpy-network-topology:topology": {
|
||||
"network_name": "EDFA Example Network - P2P",
|
||||
"elements": [
|
||||
{
|
||||
"uid": "Site_A",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site A",
|
||||
"region": "",
|
||||
"latitude": "0.0",
|
||||
"longitude": "0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"length": "80.0",
|
||||
"loss_coef": "0.200000",
|
||||
"length_units": "km",
|
||||
"att_in": "0.0",
|
||||
"con_in": "0.5",
|
||||
"con_out": "0.5",
|
||||
"pmd_coef": "0.000000000000003"
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": "1.0",
|
||||
"longitude": "0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Edfa1",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": "17.0",
|
||||
"tilt_target": "0.0",
|
||||
"out_voa": "0.0"
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": "2.0",
|
||||
"longitude": "0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Site_B",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site B",
|
||||
"region": "",
|
||||
"latitude": "2.0",
|
||||
"longitude": "0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"from_node": "Site_A",
|
||||
"to_node": "Span1"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1",
|
||||
"to_node": "Edfa1"
|
||||
},
|
||||
{
|
||||
"from_node": "Edfa1",
|
||||
"to_node": "Site_B"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
{
|
||||
"gnpy-network-topology:topology": {
|
||||
"network_name": "EDFA Example Network - P2P",
|
||||
"elements": [
|
||||
{
|
||||
"uid": "Site_A",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site A",
|
||||
"region": "",
|
||||
"latitude": "0.0",
|
||||
"longitude": "0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1",
|
||||
"type": "RamanFiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"length": "80.0",
|
||||
"loss_coef": "0.2",
|
||||
"length_units": "km",
|
||||
"att_in": "0.0",
|
||||
"con_in": "0.5",
|
||||
"con_out": "0.0",
|
||||
"lumped_losses": [
|
||||
{
|
||||
"position": "7.0",
|
||||
"loss": "0.5"
|
||||
}
|
||||
],
|
||||
"dispersion": "0.0000167",
|
||||
"effective_area": "0.000000000083",
|
||||
"pmd_coef": "0.000000000000001265",
|
||||
"raman_coefficient": {
|
||||
"reference_frequency": "206184634112792.0",
|
||||
"g0_per_frequency": [
|
||||
{
|
||||
"frequency_offset": "0.0",
|
||||
"g0": "0.0"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "500000000000.0",
|
||||
"g0": "0.000011235161"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "1000000000000.0",
|
||||
"g0": "0.0000347838074"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "1500000000000.0",
|
||||
"g0": "0.0000579356636"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "2000000000000.0",
|
||||
"g0": "0.000080692168"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "2500000000000.0",
|
||||
"g0": "0.0000979845709"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "3000000000000.0",
|
||||
"g0": "0.000110454361"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "3500000000000.0",
|
||||
"g0": "0.000118735302"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "4000000000000.0",
|
||||
"g0": "0.000124736889"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "4500000000000.0",
|
||||
"g0": "0.000130110053"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "5000000000000.0",
|
||||
"g0": "0.000141001273"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "5500000000000.0",
|
||||
"g0": "0.000146383247"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "6000000000000.0",
|
||||
"g0": "0.000157011792"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "6500000000000.0",
|
||||
"g0": "0.000170765865"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "7000000000000.0",
|
||||
"g0": "0.000188408911"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "7500000000000.0",
|
||||
"g0": "0.000205914127"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "8000000000000.0",
|
||||
"g0": "0.000224074028"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "8500000000000.0",
|
||||
"g0": "0.000247508283"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "9000000000000.0",
|
||||
"g0": "0.000277729174"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "9500000000000.0",
|
||||
"g0": "0.000308044243"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "10000000000000.0",
|
||||
"g0": "0.000334764439"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "10500000000000.0",
|
||||
"g0": "0.000356481704"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "11000000000000.0",
|
||||
"g0": "0.000377127256"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "11500000000000.0",
|
||||
"g0": "0.000396269124"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "12000000000000.0",
|
||||
"g0": "0.000410955175"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "12500000000000.0",
|
||||
"g0": "0.000418718761"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "12750000000000.0",
|
||||
"g0": "0.000419511263"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "13000000000000.0",
|
||||
"g0": "0.000417025384"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "13250000000000.0",
|
||||
"g0": "0.000413565369"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "13500000000000.0",
|
||||
"g0": "0.000407726048"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "14000000000000.0",
|
||||
"g0": "0.000383671291"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "14500000000000.0",
|
||||
"g0": "0.000408564283"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "14750000000000.0",
|
||||
"g0": "0.000369571936"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "15000000000000.0",
|
||||
"g0": "0.00031444209"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "15500000000000.0",
|
||||
"g0": "0.000216074535"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "16000000000000.0",
|
||||
"g0": "0.000123097823"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "16500000000000.0",
|
||||
"g0": "0.0000895457457"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "17000000000000.0",
|
||||
"g0": "0.00007524704"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "17500000000000.0",
|
||||
"g0": "0.0000719806145"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "18000000000000.0",
|
||||
"g0": "0.0000887961158"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "18250000000000.0",
|
||||
"g0": "0.0000930812065"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "18500000000000.0",
|
||||
"g0": "0.0000937058268"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "18750000000000.0",
|
||||
"g0": "0.0000845719619"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "19000000000000.0",
|
||||
"g0": "0.0000690585286"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "19500000000000.0",
|
||||
"g0": "0.0000450407159"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "20000000000000.0",
|
||||
"g0": "0.0000336521245"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "20500000000000.0",
|
||||
"g0": "0.0000302292475"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "21000000000000.0",
|
||||
"g0": "0.0000269376939"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "21500000000000.0",
|
||||
"g0": "0.0000260020897"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "22000000000000.0",
|
||||
"g0": "0.0000282958958"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "22500000000000.0",
|
||||
"g0": "0.0000308667558"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "23000000000000.0",
|
||||
"g0": "0.0000366024657"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "23500000000000.0",
|
||||
"g0": "0.0000580610307"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "24000000000000.0",
|
||||
"g0": "0.0000654797937"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "24500000000000.0",
|
||||
"g0": "0.0000625022715"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "25000000000000.0",
|
||||
"g0": "0.0000537806442"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "25500000000000.0",
|
||||
"g0": "0.0000394996621"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "26000000000000.0",
|
||||
"g0": "0.0000268120644"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "26500000000000.0",
|
||||
"g0": "0.0000233038554"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "27000000000000.0",
|
||||
"g0": "0.0000179140757"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "27500000000000.0",
|
||||
"g0": "0.0000152472424"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "28000000000000.0",
|
||||
"g0": "0.0000132707565"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "28500000000000.0",
|
||||
"g0": "0.000010654176"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "29000000000000.0",
|
||||
"g0": "0.00000984649374"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "29500000000000.0",
|
||||
"g0": "0.00000913999627"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "30000000000000.0",
|
||||
"g0": "0.00000908971012"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "30500000000000.0",
|
||||
"g0": "0.0000104227525"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "31000000000000.0",
|
||||
"g0": "0.0000150419271"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "31500000000000.0",
|
||||
"g0": "0.0000177838232"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "32000000000000.0",
|
||||
"g0": "0.0000215810815"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "32500000000000.0",
|
||||
"g0": "0.0000203744008"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "33000000000000.0",
|
||||
"g0": "0.0000181939341"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "33500000000000.0",
|
||||
"g0": "0.0000131862121"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "34000000000000.0",
|
||||
"g0": "0.00000965352116"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "34500000000000.0",
|
||||
"g0": "0.00000862698322"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "35000000000000.0",
|
||||
"g0": "0.00000918688016"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "35500000000000.0",
|
||||
"g0": "0.0000101737784"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "36000000000000.0",
|
||||
"g0": "0.0000108017817"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "36500000000000.0",
|
||||
"g0": "0.0000103903588"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "37000000000000.0",
|
||||
"g0": "0.00000930040333"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "37500000000000.0",
|
||||
"g0": "0.00000830809173"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "38000000000000.0",
|
||||
"g0": "0.00000690650401"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "38500000000000.0",
|
||||
"g0": "0.00000552238029"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "39000000000000.0",
|
||||
"g0": "0.00000390648708"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "39500000000000.0",
|
||||
"g0": "0.00000222908227"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "40000000000000.0",
|
||||
"g0": "0.00000155796177"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "40500000000000.0",
|
||||
"g0": "0.00000097721872"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "41000000000000.0",
|
||||
"g0": "0.00000032347724"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "41500000000000.0",
|
||||
"g0": "0.00000016060245"
|
||||
},
|
||||
{
|
||||
"frequency_offset": "42000000000000.0",
|
||||
"g0": "0.00000007973064"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"operational": {
|
||||
"temperature": "283.0",
|
||||
"raman_pumps": [
|
||||
{
|
||||
"frequency": "205000000000000.0",
|
||||
"power": "0.2",
|
||||
"propagation_direction": "counterprop"
|
||||
},
|
||||
{
|
||||
"frequency": "201000000000000.0",
|
||||
"power": "0.206",
|
||||
"propagation_direction": "counterprop"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": "1.0",
|
||||
"longitude": "0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Edfa1",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": "17.0",
|
||||
"tilt_target": "0.0",
|
||||
"out_voa": "0.0"
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": "2.0",
|
||||
"longitude": "0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Site_B",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site B",
|
||||
"region": "",
|
||||
"latitude": "2.0",
|
||||
"longitude": "0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"from_node": "Site_A",
|
||||
"to_node": "Span1"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1",
|
||||
"to_node": "Edfa1"
|
||||
},
|
||||
{
|
||||
"from_node": "Edfa1",
|
||||
"to_node": "Site_B"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
381
tests/data/convert/GNPy_yang_formatted-eqpt_config_expected.json
Normal file
381
tests/data/convert/GNPy_yang_formatted-eqpt_config_expected.json
Normal file
@@ -0,0 +1,381 @@
|
||||
{
|
||||
"gnpy-eqpt-config:equipment": {
|
||||
"Edfa": [
|
||||
{
|
||||
"type_variety": "CienaDB_medium_gain",
|
||||
"type_def": "advanced_model",
|
||||
"gain_flatmax": "25.0",
|
||||
"gain_min": "15.0",
|
||||
"p_max": "21.0",
|
||||
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": "26.0",
|
||||
"gain_min": "15.0",
|
||||
"p_max": "21.0",
|
||||
"nf_min": "6.0",
|
||||
"nf_max": "10.0",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": "16.0",
|
||||
"gain_min": "8.0",
|
||||
"p_max": "21.0",
|
||||
"nf_min": "7.0",
|
||||
"nf_max": "11.0",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "test",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": "25.0",
|
||||
"gain_min": "15.0",
|
||||
"p_max": "21.0",
|
||||
"nf_min": "5.8",
|
||||
"nf_max": "10.0",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "test_fixed_gain",
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": "21.0",
|
||||
"gain_min": "20.0",
|
||||
"p_max": "21.0",
|
||||
"nf0": "5.0",
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_booster",
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": "21.0",
|
||||
"gain_min": "20.0",
|
||||
"p_max": "21.0",
|
||||
"nf0": "5.0",
|
||||
"allowed_for_design": false
|
||||
}
|
||||
],
|
||||
"Fiber": [
|
||||
{
|
||||
"type_variety": "SSMF",
|
||||
"dispersion": "0.0000167",
|
||||
"effective_area": "0.000000000083",
|
||||
"pmd_coef": "0.000000000000001265"
|
||||
}
|
||||
],
|
||||
"Span": [
|
||||
{
|
||||
"power_mode": true,
|
||||
"max_fiber_lineic_loss_for_raman": "0.25",
|
||||
"target_extended_gain": "2.5",
|
||||
"max_length": "150.0",
|
||||
"length_units": "km",
|
||||
"max_loss": "28.0",
|
||||
"padding": "10.0",
|
||||
"EOL": "0.0",
|
||||
"con_in": "0.0",
|
||||
"con_out": "0.0",
|
||||
"delta_power_range_dict_db": {
|
||||
"min_value": "0.0",
|
||||
"max_value": "0.0",
|
||||
"step": "0.5"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Roadm": [
|
||||
{
|
||||
"type_variety": "example_test",
|
||||
"target_pch_out_db": "-18.0",
|
||||
"add_drop_osnr": "35.0",
|
||||
"pmd": "0.000000000001",
|
||||
"pdl": "0.5",
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
},
|
||||
"roadm-path-impairments": []
|
||||
},
|
||||
{
|
||||
"type_variety": "example_detailed_impairments",
|
||||
"target_pch_out_db": "-20.0",
|
||||
"add_drop_osnr": "35.0",
|
||||
"pmd": "0.0",
|
||||
"pdl": "0.0",
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
},
|
||||
"roadm-path-impairments": [
|
||||
{
|
||||
"roadm-path-impairments-id": 0,
|
||||
"roadm-express-path": [
|
||||
{
|
||||
"frequency-range": {
|
||||
"lower-frequency": "191300000000000.0",
|
||||
"upper-frequency": "196100000000000.0"
|
||||
},
|
||||
"roadm-pmd": "0.0",
|
||||
"roadm-cd": "0.0",
|
||||
"roadm-pdl": "0.0",
|
||||
"roadm-inband-crosstalk": "0.0",
|
||||
"roadm-maxloss": "16.5"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"roadm-path-impairments-id": 1,
|
||||
"roadm-add-path": [
|
||||
{
|
||||
"frequency-range": {
|
||||
"lower-frequency": "191300000000000.0",
|
||||
"upper-frequency": "196100000000000.0"
|
||||
},
|
||||
"roadm-pmd": "0.0",
|
||||
"roadm-cd": "0.0",
|
||||
"roadm-pdl": "0.0",
|
||||
"roadm-inband-crosstalk": "0.0",
|
||||
"roadm-maxloss": "11.5",
|
||||
"roadm-pmax": "2.5",
|
||||
"roadm-osnr": "41.0",
|
||||
"roadm-noise-figure": "23.0"
|
||||
},
|
||||
{
|
||||
"frequency-range": {
|
||||
"lower-frequency": "186300000000000.0",
|
||||
"upper-frequency": "190100000000000.0"
|
||||
},
|
||||
"roadm-pmd": "0.0",
|
||||
"roadm-cd": "0.0",
|
||||
"roadm-pdl": "0.5",
|
||||
"roadm-inband-crosstalk": "0.0",
|
||||
"roadm-maxloss": "5.0",
|
||||
"roadm-pmax": "0.0",
|
||||
"roadm-osnr": "35.0",
|
||||
"roadm-noise-figure": "6.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"roadm-path-impairments-id": 2,
|
||||
"roadm-drop-path": [
|
||||
{
|
||||
"frequency-range": {
|
||||
"lower-frequency": "191300000000000.0",
|
||||
"upper-frequency": "196100000000000.0"
|
||||
},
|
||||
"roadm-pmd": "0.0",
|
||||
"roadm-cd": "0.0",
|
||||
"roadm-pdl": "0.0",
|
||||
"roadm-inband-crosstalk": "0.0",
|
||||
"roadm-maxloss": "11.5",
|
||||
"roadm-minloss": "7.5",
|
||||
"roadm-typloss": "10.0",
|
||||
"roadm-pmin": "-13.5",
|
||||
"roadm-pmax": "-9.5",
|
||||
"roadm-ptyp": "-12.0",
|
||||
"roadm-osnr": "41.0",
|
||||
"roadm-noise-figure": "15.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type_variety": "default",
|
||||
"target_pch_out_db": "-20.0",
|
||||
"add_drop_osnr": "38.0",
|
||||
"pmd": "0.0",
|
||||
"pdl": "0.0",
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type_variety": "detailed_impairments",
|
||||
"target_pch_out_db": "-20.0",
|
||||
"add_drop_osnr": "35.0",
|
||||
"pmd": "0.0",
|
||||
"pdl": "0.0",
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
},
|
||||
"roadm-path-impairments": [
|
||||
{
|
||||
"roadm-path-impairments-id": 0,
|
||||
"roadm-express-path": [
|
||||
{
|
||||
"frequency-range": {
|
||||
"lower-frequency": "191300000000000.0",
|
||||
"upper-frequency": "196100000000000.0"
|
||||
},
|
||||
"roadm-pmd": "0.0",
|
||||
"roadm-cd": "0.0",
|
||||
"roadm-pdl": "0.0",
|
||||
"roadm-inband-crosstalk": "0.0",
|
||||
"roadm-maxloss": "16.5"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SI": [
|
||||
{
|
||||
"type_variety": "default",
|
||||
"f_min": "191300000000000.0",
|
||||
"f_max": "196100000000000.0",
|
||||
"baud_rate": "32000000000.0",
|
||||
"spacing": "50000000000.0",
|
||||
"power_dbm": "0.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "100.0",
|
||||
"sys_margins": "0.0",
|
||||
"use_si_channel_count_for_design": false,
|
||||
"power_range_dict_db": {
|
||||
"min_value": "0.0",
|
||||
"max_value": "0.0",
|
||||
"step": "0.5"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Transceiver": [
|
||||
{
|
||||
"type_variety": "vendorA_trx-type1",
|
||||
"frequency": {
|
||||
"min": "191350000000000.0",
|
||||
"max": "196100000000000.0"
|
||||
},
|
||||
"mode": [
|
||||
{
|
||||
"format": "PS_SP64_1",
|
||||
"baud_rate": "32000000000.0",
|
||||
"OSNR": "11.0",
|
||||
"bit_rate": "100000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "100.0",
|
||||
"min_spacing": "50000000000.0",
|
||||
"cost": "1.0"
|
||||
},
|
||||
{
|
||||
"format": "PS_SP64_2",
|
||||
"baud_rate": "64000000000.0",
|
||||
"OSNR": "15.0",
|
||||
"bit_rate": "200000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "100.0",
|
||||
"min_spacing": "75000000000.0",
|
||||
"cost": "1.0"
|
||||
},
|
||||
{
|
||||
"format": "mode 1",
|
||||
"baud_rate": "32000000000.0",
|
||||
"OSNR": "11.0",
|
||||
"bit_rate": "100000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "100.0",
|
||||
"min_spacing": "50000000000.0",
|
||||
"cost": "1.0"
|
||||
},
|
||||
{
|
||||
"format": "mode 2",
|
||||
"baud_rate": "64000000000.0",
|
||||
"OSNR": "15.0",
|
||||
"bit_rate": "200000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "100.0",
|
||||
"min_spacing": "75000000000.0",
|
||||
"cost": "1.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type_variety": "Voyager_16QAM",
|
||||
"frequency": {
|
||||
"min": "191350000000000.0",
|
||||
"max": "196100000000000.0"
|
||||
},
|
||||
"mode": [
|
||||
{
|
||||
"format": "16QAM",
|
||||
"baud_rate": "32000000000.0",
|
||||
"OSNR": "19.0",
|
||||
"bit_rate": "200000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "100.0",
|
||||
"min_spacing": "50000000000.0",
|
||||
"cost": "1.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type_variety": "Voyager",
|
||||
"frequency": {
|
||||
"min": "191350000000000.0",
|
||||
"max": "196100000000000.0"
|
||||
},
|
||||
"mode": [
|
||||
{
|
||||
"format": "mode 1",
|
||||
"baud_rate": "32000000000.0",
|
||||
"OSNR": "12.0",
|
||||
"bit_rate": "100000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "45.0",
|
||||
"min_spacing": "50000000000.0",
|
||||
"cost": "1.0"
|
||||
},
|
||||
{
|
||||
"format": "mode 3",
|
||||
"baud_rate": "44000000000.0",
|
||||
"OSNR": "18.0",
|
||||
"bit_rate": "300000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "45.0",
|
||||
"min_spacing": "62500000000.0",
|
||||
"cost": "1.0"
|
||||
},
|
||||
{
|
||||
"format": "mode 2",
|
||||
"baud_rate": "66000000000.0",
|
||||
"OSNR": "21.0",
|
||||
"bit_rate": "400000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "45.0",
|
||||
"min_spacing": "75000000000.0",
|
||||
"cost": "1.0"
|
||||
},
|
||||
{
|
||||
"format": "mode 2 - fake",
|
||||
"baud_rate": "66000000000.0",
|
||||
"OSNR": "21.0",
|
||||
"bit_rate": "400000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "45.0",
|
||||
"min_spacing": "75000000000.0",
|
||||
"cost": "1.0"
|
||||
},
|
||||
{
|
||||
"format": "mode 4",
|
||||
"baud_rate": "66000000000.0",
|
||||
"OSNR": "16.0",
|
||||
"bit_rate": "200000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "45.0",
|
||||
"min_spacing": "75000000000.0",
|
||||
"cost": "1.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"gnpy-eqpt-config:equipment": {
|
||||
"Transceiver": [
|
||||
{
|
||||
"type_variety": "ZR400G",
|
||||
"frequency": {
|
||||
"min": "191350000000000.0",
|
||||
"max": "196100000000000.0"
|
||||
},
|
||||
"mode": [
|
||||
{
|
||||
"format": "400G",
|
||||
"baud_rate": "60000000000.0",
|
||||
"OSNR": "24.0",
|
||||
"bit_rate": "400000000000.0",
|
||||
"roll_off": "0.2",
|
||||
"tx_osnr": "38.0",
|
||||
"min_spacing": "75000000000.0",
|
||||
"cost": "1.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Edfa": [
|
||||
{
|
||||
"type_variety": "user_defined_default_amplifier",
|
||||
"type_def": "advanced_model",
|
||||
"gain_flatmax": "25.0",
|
||||
"gain_min": "15.0",
|
||||
"p_max": "21.0",
|
||||
"advanced_config_from_json": "default_edfa_config.json",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"gnpy-sim-params:sim-params": {
|
||||
"raman_params": {
|
||||
"flag": true,
|
||||
"result_spatial_resolution": "10000.0",
|
||||
"solver_spatial_resolution": "10000.0"
|
||||
},
|
||||
"nli_params": {
|
||||
"method": "ggn_spectrally_separated",
|
||||
"dispersion_tolerance": "1.0",
|
||||
"phase_shift_tolerance": "0.1",
|
||||
"computed_channels": [
|
||||
1,
|
||||
18,
|
||||
37,
|
||||
56,
|
||||
75
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"gnpy-spectrum:spectrum": [
|
||||
{
|
||||
"f_min": "191400000000000.0",
|
||||
"f_max": "193100000000000.0",
|
||||
"baud_rate": "32000000000.0",
|
||||
"slot_width": "50000000000.0",
|
||||
"delta_pdb": "0.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "40.0",
|
||||
"label": "mode_1"
|
||||
},
|
||||
{
|
||||
"f_min": "193162500000000.0",
|
||||
"f_max": "195000000000000.0",
|
||||
"baud_rate": "64000000000.0",
|
||||
"slot_width": "75000000000.0",
|
||||
"roll_off": "0.15",
|
||||
"tx_osnr": "40.0",
|
||||
"tx_power_dbm": "-10.0",
|
||||
"label": "mode_2"
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user