mirror of
				https://github.com/Telecominfraproject/oopt-gnpy.git
				synced 2025-10-31 18:18:00 +00:00 
			
		
		
		
	Compare commits
	
		
			79 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d28c67143e | ||
|   | 6bb9ae8336 | ||
|   | 0dc7d853ef | ||
|   | dec9388416 | ||
|   | 017b35fa33 | ||
|   | cb0a410418 | ||
|   | f250990a49 | ||
|   | 280443f17f | ||
|   | 6f62251cb4 | ||
|   | 5ad54879b1 | ||
|   | 825d37c05c | ||
|   | 3ac9f90914 | ||
|   | dbfbf115ff | ||
|   | ad2590962b | ||
|   | a9d530c776 | ||
|   | f255c31f1f | ||
|   | 80ec05f84c | ||
|   | 22541d65e4 | ||
|   | 26fcf0ff6e | ||
|   | 1c32e437a2 | ||
|   | 718007b3de | ||
|   | 4d6c06340f | ||
|   | bad893bf86 | ||
|   | 75e7fca8e4 | ||
|   | 4e38ba98ab | ||
|   | fdcdfca589 | ||
|   | 299ca10a47 | ||
|   | c0b7bf714e | ||
|   | 7f7c568160 | ||
|   | 9bf6ed953a | ||
|   | e68dc39ddd | ||
|   | f8007b41d1 | ||
|   | 228125029e | ||
|   | d185e0c241 | ||
|   | 357bbec257 | ||
|   | d25e98c567 | ||
|   | 397411690e | ||
|   | 4ab6f8cb1b | ||
|   | 44aff147db | ||
|   | a36b139065 | ||
|   | 141fc66d47 | ||
|   | 53f29957fd | ||
|   | 9f3995ee20 | ||
|   | 0cf45bd102 | ||
|   | 55932ee3e9 | ||
|   | 797a0856ec | ||
|   | 3fa53adc4d | ||
|   | bcb5e6bb60 | ||
|   | 6380f8f37a | ||
|   | 93869d6cb5 | ||
|   | ce51a4d160 | ||
|   | 601e228bb6 | ||
|   | 3f58cbd559 | ||
|   | 2e3274ac78 | ||
|   | e33144f8cc | ||
|   | fd1e3f0f61 | ||
|   | 80c41264cf | ||
|   | a051a5723b | ||
|   | 72f300ab94 | ||
|   | 2c3b0d8c82 | ||
|   | 11dab614a9 | ||
|   | 11d88bf09a | ||
|   | af3cc4736e | ||
|   | 50cb82ee18 | ||
|   | c80aca6696 | ||
|   | dfca35d4ae | ||
|   | 1fbdaef58a | ||
|   | bd025f3af4 | ||
|   | c3e546abe3 | ||
|   | 9427d0b139 | ||
|   | 89f5b12f7e | ||
|   | 9d2c10e267 | ||
|   | 305620e5dd | ||
|   | c91c5d622f | ||
|   | 24e7f4a5a1 | ||
|   | 08c922a5e5 | ||
|   | efd7468d42 | ||
|   | 902cfa11a7 | ||
|   | 24c6acc027 | 
							
								
								
									
										111
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| on: | ||||
|   push: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|  | ||||
| name: CI | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     name: Tox test | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|       - uses: fedora-python/tox-github-action@v0.4 | ||||
|         with: | ||||
|           tox_env: ${{ matrix.tox_env }} | ||||
|           dnf_install: ${{ matrix.dnf_install }} | ||||
|       - uses: codecov/codecov-action@29386c70ef20e286228c72b668a06fd0e8399192 | ||||
|         if: ${{ endswith(matrix.tox_env, '-cover') }} | ||||
|         with: | ||||
|           files: ${{ github.workspace }}/cover/coverage.xml | ||||
|     strategy: | ||||
|       matrix: | ||||
|         tox_env: | ||||
|           - py38 | ||||
|           - py39-cover | ||||
|         include: | ||||
|           - tox_env: docs | ||||
|             dnf_install: graphviz | ||||
|  | ||||
|   pypi: | ||||
|     needs: build | ||||
|     if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && github.repository_owner == 'Telecominfraproject' }} | ||||
|     name: PyPI packaging | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|       - uses: actions/setup-python@v2 | ||||
|         name: Install Python | ||||
|         with: | ||||
|           python-version: '3.9' | ||||
|       - uses: casperdcl/deploy-pypi@bb869aafd89f657ceaafe9561d3b5584766c0f95 | ||||
|         with: | ||||
|           password: ${{ secrets.PYPI_API_TOKEN }} | ||||
|           pip: wheel -w dist/ --no-deps . | ||||
|           upload: true | ||||
|  | ||||
|   docker: | ||||
|     needs: build | ||||
|     if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')) && github.repository_owner == 'Telecominfraproject' }} | ||||
|     name: Docker image | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Log in to Docker Hub | ||||
|         uses: docker/login-action@v1 | ||||
|         with: | ||||
|           username: jktjkt | ||||
|           password: ${{ secrets.DOCKERHUB_TOKEN }} | ||||
|       - uses: actions/checkout@v2 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|       - name: Extract tag name | ||||
|         if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} | ||||
|         id: extract_pretty_git | ||||
|         run: echo ::set-output name=GIT_DESC::$(git describe --tags) | ||||
|       - name: Build and push a container | ||||
|         uses: docker/build-push-action@v2 | ||||
|         if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} | ||||
|         with: | ||||
|           context: . | ||||
|           push: true | ||||
|           tags: | | ||||
|             telecominfraproject/oopt-gnpy:${{ steps.extract_pretty_git.outputs.GIT_DESC }} | ||||
|             telecominfraproject/oopt-gnpy:master | ||||
|       - name: Extract tag name | ||||
|         if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} | ||||
|         id: extract_tag_name | ||||
|         run: echo ::set-output name=GIT_DESC::${GITHUB_REF/refs\/tags\//} | ||||
|       - name: Build and push a container | ||||
|         uses: docker/build-push-action@v2 | ||||
|         if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} | ||||
|         with: | ||||
|           context: . | ||||
|           push: true | ||||
|           tags: | | ||||
|             telecominfraproject/oopt-gnpy:${{ steps.extract_tag_name.outputs.GIT_DESC }} | ||||
|             telecominfraproject/oopt-gnpy:latest | ||||
|  | ||||
|   windows: | ||||
|     name: Tests on Windows | ||||
|     runs-on: windows-2019 | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|       - uses: actions/setup-python@v2 | ||||
|         with: | ||||
|           python-version: ${{ matrix.python_version }} | ||||
|       - run: | | ||||
|           pip install --editable . | ||||
|           pip install 'pytest>=5.0.0,<6' | ||||
|           pytest -vv | ||||
|     strategy: | ||||
|       matrix: | ||||
|         python_version: | ||||
|           - "3.9" | ||||
| @@ -3,8 +3,6 @@ os: linux | ||||
| language: python | ||||
| services: docker | ||||
| python: | ||||
|   - "3.6" | ||||
|   - "3.7" | ||||
|   - "3.8" | ||||
|   - "3.9" | ||||
| before_install: | ||||
|   | ||||
							
								
								
									
										21
									
								
								.zuul.yaml
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								.zuul.yaml
									
									
									
									
									
								
							| @@ -2,24 +2,25 @@ | ||||
| - project: | ||||
|     check: | ||||
|       jobs: | ||||
|         - tox-py38-cover | ||||
|         - tox-py38-f34 | ||||
|         - tox-py39-cover | ||||
|         - tox-docs-f34 | ||||
|         - coverage-diff: | ||||
|             voting: false | ||||
|             dependencies: | ||||
|               - tox-py38-cover-previous | ||||
|               - tox-py38-cover | ||||
|               - tox-py39-cover-previous | ||||
|               - tox-py39-cover | ||||
|             vars: | ||||
|               coverage_job_name_previous: tox-py38-cover-previous | ||||
|               coverage_job_name_current: tox-py38-cover | ||||
|               coverage_job_name_previous: tox-py39-cover-previous | ||||
|               coverage_job_name_current: tox-py39-cover | ||||
|         - tox-linters-diff-n-report: | ||||
|             voting: false | ||||
|         - tox-py36-el8 | ||||
|         - tox-docs-f32 | ||||
|         - tox-py38-cover-previous | ||||
|         - tox-py39-cover-previous | ||||
|     gate: | ||||
|       jobs: | ||||
|         - tox-py38-f32 | ||||
|         - tox-docs-f32 | ||||
|         - tox-py38-f34 | ||||
|         - tox-py39-f34 | ||||
|         - tox-docs-f34 | ||||
|     tag: | ||||
|       jobs: | ||||
|         - oopt-release-python: | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| [](https://pypi.org/project/gnpy/) | ||||
| [](https://pypi.org/project/gnpy/) | ||||
| [](http://gnpy.readthedocs.io/en/master/?badge=master) | ||||
| [](https://travis-ci.com/Telecominfraproject/oopt-gnpy) | ||||
| [](https://github.com/Telecominfraproject/oopt-gnpy/actions/workflows/main.yml) | ||||
| [](https://review.gerrithub.io/q/project:Telecominfraproject/oopt-gnpy+is:open) | ||||
| [](https://github.com/Telecominfraproject/oopt-gnpy/graphs/contributors) | ||||
| [](https://lgtm.com/projects/g/Telecominfraproject/oopt-gnpy/) | ||||
| @@ -18,12 +18,12 @@ Together, we are building this tool for rapid development of production-grade ro | ||||
|  | ||||
| ## Quick Start | ||||
|  | ||||
| Install either via [Docker](docs/install.rst#install-docker), or as a [Python package](docs/install.rst#install-pip). | ||||
| Install either via [Docker](https://gnpy.readthedocs.io/en/master/install.html#using-prebuilt-docker-images), or as a [Python package](https://gnpy.readthedocs.io/en/master/install.html#using-python-on-your-computer). | ||||
| Read our [documentation](https://gnpy.readthedocs.io/), learn from the demos, and [get in touch with us](https://github.com/Telecominfraproject/oopt-gnpy/discussions). | ||||
|  | ||||
| This example demonstrates how GNPy can be used to check the expected SNR at the end of the line by varying the channel input power: | ||||
|  | ||||
| [](https://asciinema.org/a/252295) | ||||
|  | ||||
|  | ||||
| GNPy can do much more, including acting as a Path Computation Engine, tracking bandwidth requests, or advising the SDN controller about a best possible path through a large DWDM network. | ||||
| Learn more about this [in the documentation](https://gnpy.readthedocs.io/). | ||||
|   | ||||
| @@ -29,6 +29,7 @@ This path is directional, and all "GNPy elements" along the path match the unidi | ||||
|  | ||||
| The network topology contains not just the physical topology of the network, but also references to the :ref:`equipment library<concepts-equipment>` and a set of *operating parameters* for each entity. | ||||
| These parameters include the **fiber length** of each fiber, the connector **attenutation losses**, or an amplifier's specific **gain setting**. | ||||
| The topology is specified via :ref:`XLS files<excel>` or via :ref:`JSON<json>`. | ||||
|  | ||||
| .. _complete-vs-incomplete: | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| .. _excel: | ||||
|  | ||||
| Excel (XLS, XLSX) input files | ||||
| ============================= | ||||
|  | ||||
|   | ||||
| @@ -38,7 +38,7 @@ Using Python on your computer | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|    **Note**: `gnpy` supports Python 3 only. Python 2 is not supported. | ||||
|    `gnpy` requires Python ≥3.6 | ||||
|    `gnpy` requires Python ≥3.8 | ||||
|  | ||||
|    **Note**: the `gnpy` maintainers strongly recommend the use of Anaconda for | ||||
|    managing dependencies. | ||||
| @@ -84,7 +84,7 @@ exact version of Python you are using. | ||||
|     $ which python                   # check which Python executable is used | ||||
|     /path/to/anaconda/bin/python | ||||
|     $ python -V                      # check your Python version | ||||
|     Python 3.6.5 :: Anaconda, Inc. | ||||
|     Python 3.8.0 :: Anaconda, Inc. | ||||
|  | ||||
| .. _install-pip: | ||||
|  | ||||
|   | ||||
| @@ -20,7 +20,6 @@ This example demonstrates how GNPy can be used to check the expected SNR at the | ||||
|    :width: 100% | ||||
|    :align: left | ||||
|    :alt: Running a simple simulation example | ||||
|    :target: https://asciinema.org/a/252295 | ||||
|  | ||||
| By default, this script operates on a single span network defined in | ||||
| `gnpy/example-data/edfa_example_network.json <gnpy/example-data/edfa_example_network.json>`_ | ||||
| @@ -92,4 +91,4 @@ As a result transponder type is not part of the network info. it is related to t | ||||
|  | ||||
| The current version includes a spectrum assigment features that enables to compute a candidate spectrum assignment for each service based on a first fit policy. Spectrum is assigned based on service specified spacing value, path_bandwidth value and selected mode for the transceiver. This spectrum assignment includes a basic capacity planning capability so that the spectrum resource is limited by the frequency min and max values defined for the links. If the requested services reach the link spectrum capacity, additional services feasibility are computed but marked as blocked due to spectrum reason. | ||||
|  | ||||
| OpenROADM networks can be simulated via ``gnpy/example-data/eqpt_config_openroadm.json`` -- see ``gnpy/example-data/Sweden_OpenROADM_example_network.json`` as an example.  | ||||
| OpenROADM networks can be simulated via ``gnpy/example-data/eqpt_config_openroadm_*.json`` -- see ``gnpy/example-data/Sweden_OpenROADM*_example_network.json`` as an example.  | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| .. _json: | ||||
|  | ||||
| JSON Input Files | ||||
| ================ | ||||
|  | ||||
|   | ||||
| @@ -614,8 +614,8 @@ class Edfa(_Node): | ||||
|                           f'  pad att_in (dB):        {self.att_in:.2f}', | ||||
|                           f'  Power In (dBm):         {self.pin_db:.2f}', | ||||
|                           f'  Power Out (dBm):        {self.pout_db:.2f}', | ||||
|                           f'  Delta_P (dB):           ' + f'{self.delta_p:.2f}' if self.delta_p is not None else 'None', | ||||
|                           f'  target pch (dBm):       ' + f'{self.target_pch_out_db:.2f}' if self.target_pch_out_db is not None else 'None', | ||||
|                           f'  Delta_P (dB):           ' + (f'{self.delta_p:.2f}' if self.delta_p is not None else 'None'), | ||||
|                           f'  target pch (dBm):       ' + (f'{self.target_pch_out_db:.2f}' if self.target_pch_out_db is not None else 'None'), | ||||
|                           f'  effective pch (dBm):    {self.effective_pch_out_db:.2f}', | ||||
|                           f'  output VOA (dB):        {self.out_voa:.2f}']) | ||||
|  | ||||
|   | ||||
| @@ -269,7 +269,7 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d | ||||
|                 node_loss = span_loss(network, prev_node) | ||||
|                 voa = node.out_voa if node.out_voa else 0 | ||||
|                 if node.delta_p is None: | ||||
|                     dp = target_power(network, next_node, equipment) | ||||
|                     dp = target_power(network, next_node, equipment) + voa | ||||
|                 else: | ||||
|                     dp = node.delta_p | ||||
|                 if node.effective_gain is None or power_mode: | ||||
| @@ -511,12 +511,12 @@ def add_fiber_padding(network, fibers, padding): | ||||
|                 first_fiber.params.att_in = first_fiber.params.att_in + padding - this_span_loss | ||||
|  | ||||
|  | ||||
| def build_network(network, equipment, pref_ch_db, pref_total_db): | ||||
| def build_network(network, equipment, pref_ch_db, pref_total_db, no_insert_edfas=False): | ||||
|     default_span_data = equipment['Span']['default'] | ||||
|     max_length = int(convert_length(default_span_data.max_length, default_span_data.length_units)) | ||||
|     min_length = max(int(default_span_data.padding / 0.2 * 1e3), 50_000) | ||||
|     bounds = range(min_length, max_length) | ||||
|     target_length = max(min_length, 90_000) | ||||
|     target_length = max(min_length, min(max_length, 90_000)) | ||||
|  | ||||
|     # set roadm loss for gain_mode before to build network | ||||
|     fibers = [f for f in network.nodes() if isinstance(f, elements.Fiber)] | ||||
| @@ -524,17 +524,20 @@ def build_network(network, equipment, pref_ch_db, pref_total_db): | ||||
|     add_fiber_padding(network, fibers, default_span_data.padding) | ||||
|     # don't group split fiber and add amp in the same loop | ||||
|     # =>for code clarity (at the expense of speed): | ||||
|     for fiber in fibers: | ||||
|         split_fiber(network, fiber, bounds, target_length, equipment) | ||||
|  | ||||
|     roadms = [r for r in network.nodes() if isinstance(r, elements.Roadm)] | ||||
|     for roadm in roadms: | ||||
|         add_roadm_preamp(network, roadm) | ||||
|         add_roadm_booster(network, roadm) | ||||
|  | ||||
|     fibers = [f for f in network.nodes() if isinstance(f, elements.Fiber)] | ||||
|     for fiber in fibers: | ||||
|         add_inline_amplifier(network, fiber) | ||||
|     if not no_insert_edfas: | ||||
|         for fiber in fibers: | ||||
|             split_fiber(network, fiber, bounds, target_length, equipment) | ||||
|  | ||||
|         for roadm in roadms: | ||||
|             add_roadm_preamp(network, roadm) | ||||
|             add_roadm_booster(network, roadm) | ||||
|  | ||||
|         fibers = [f for f in network.nodes() if isinstance(f, elements.Fiber)] | ||||
|         for fiber in fibers: | ||||
|             add_inline_amplifier(network, fiber) | ||||
|  | ||||
|     for roadm in roadms: | ||||
|         set_egress_amplifier(network, roadm, equipment, pref_ch_db, pref_total_db) | ||||
|   | ||||
| @@ -107,6 +107,35 @@ def db2lin(value): | ||||
|  | ||||
|  | ||||
| def round2float(number, step): | ||||
|     """Round a floating point number so that its "resolution" is not bigger than 'step' | ||||
|  | ||||
|     The finest step is fixed at 0.01; smaller values are silently changed to 0.01. | ||||
|  | ||||
|     >>> round2float(123.456, 1000) | ||||
|     0.0 | ||||
|     >>> round2float(123.456, 100) | ||||
|     100.0 | ||||
|     >>> round2float(123.456, 10) | ||||
|     120.0 | ||||
|     >>> round2float(123.456, 1) | ||||
|     123.0 | ||||
|     >>> round2float(123.456, 0.1) | ||||
|     123.5 | ||||
|     >>> round2float(123.456, 0.01) | ||||
|     123.46 | ||||
|     >>> round2float(123.456, 0.001) | ||||
|     123.46 | ||||
|     >>> round2float(123.249, 0.5) | ||||
|     123.0 | ||||
|     >>> round2float(123.250, 0.5) | ||||
|     123.0 | ||||
|     >>> round2float(123.251, 0.5) | ||||
|     123.5 | ||||
|     >>> round2float(123.300, 0.2) | ||||
|     123.2 | ||||
|     >>> round2float(123.301, 0.2) | ||||
|     123.4 | ||||
|     """ | ||||
|     step = round(step, 1) | ||||
|     if step >= 0.01: | ||||
|         number = round(number / step, 0) | ||||
|   | ||||
							
								
								
									
										6233
									
								
								gnpy/example-data/Sweden_OpenROADMv5_example_network.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6233
									
								
								gnpy/example-data/Sweden_OpenROADMv5_example_network.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -55,6 +55,24 @@ | ||||
|             "allowed_for_design": false | ||||
|             }, | ||||
|             { | ||||
|             "type_variety": "openroadm_mw_mw_preamp_typical_ver5", | ||||
|             "type_def": "openroadm", | ||||
|             "gain_flatmax": 27, | ||||
|             "gain_min": 0, | ||||
|             "p_max": 22, | ||||
|             "nf_coef": [-5.952e-4,-6.250e-2,-1.071,28.99], | ||||
|             "allowed_for_design": false | ||||
|             }, | ||||
|             { | ||||
|             "type_variety": "openroadm_mw_mw_preamp_worstcase_ver5", | ||||
|             "type_def": "openroadm", | ||||
|             "gain_flatmax": 27, | ||||
|             "gain_min": 0, | ||||
|             "p_max": 22, | ||||
|             "nf_coef": [-5.952e-4,-6.250e-2,-1.071,27.99], | ||||
|             "allowed_for_design": false | ||||
|             }, | ||||
|             { | ||||
|             "type_variety": "openroadm_mw_mw_booster", | ||||
|             "type_def": "openroadm_booster", | ||||
|             "gain_flatmax": 32, | ||||
|   | ||||
							
								
								
									
										210
									
								
								gnpy/example-data/eqpt_config_openroadm_ver5.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								gnpy/example-data/eqpt_config_openroadm_ver5.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | ||||
| {     "Edfa":[ | ||||
|             { | ||||
|             "type_variety": "openroadm_ila_low_noise", | ||||
|             "type_def": "openroadm", | ||||
|             "gain_flatmax": 27, | ||||
|             "gain_min": 0, | ||||
|             "p_max": 22, | ||||
|             "nf_coef": [-8.104e-4,-6.221e-2,-5.889e-1,37.62], | ||||
|             "allowed_for_design": true | ||||
|             }, | ||||
|             { | ||||
|             "type_variety": "openroadm_ila_standard", | ||||
|             "type_def": "openroadm", | ||||
|             "gain_flatmax": 27, | ||||
|             "gain_min": 0, | ||||
|             "p_max": 22, | ||||
|             "nf_coef": [-5.952e-4,-6.250e-2,-1.071,28.99], | ||||
|             "allowed_for_design": true | ||||
|             }, | ||||
| 		{ | ||||
|             "type_variety": "openroadm_mw_mw_preamp_typical_ver5", | ||||
|             "type_def": "openroadm", | ||||
|             "gain_flatmax": 27, | ||||
|             "gain_min": 0, | ||||
|             "p_max": 22, | ||||
|             "nf_coef": [-5.952e-4,-6.250e-2,-1.071,28.99], | ||||
|             "allowed_for_design": false | ||||
|             }, | ||||
|             { | ||||
|             "type_variety": "openroadm_mw_mw_preamp_worstcase_ver5", | ||||
|             "type_def": "openroadm", | ||||
|             "gain_flatmax": 27, | ||||
|             "gain_min": 0, | ||||
|             "p_max": 22, | ||||
|             "nf_coef": [-5.952e-4,-6.250e-2,-1.071,27.99], | ||||
|             "allowed_for_design": false | ||||
|             }, | ||||
| 		{ | ||||
|             "type_variety": "openroadm_mw_mw_booster", | ||||
|             "type_def": "openroadm_booster", | ||||
|             "gain_flatmax": 32, | ||||
|             "gain_min": 0, | ||||
|             "p_max": 22, | ||||
|             "allowed_for_design": false | ||||
|             } | ||||
|       ], | ||||
|       "Fiber":[ | ||||
|             { | ||||
|             "type_variety": "SSMF", | ||||
|             "dispersion": 1.67e-05, | ||||
|             "gamma": 0.00127, | ||||
|             "pmd_coef": 1.265e-15 | ||||
|             }, | ||||
|             { | ||||
|             "type_variety": "NZDF", | ||||
|             "dispersion": 0.5e-05, | ||||
|             "gamma": 0.00146, | ||||
|             "pmd_coef": 1.265e-15 | ||||
|             }, | ||||
|             { | ||||
|             "type_variety": "LOF", | ||||
|             "dispersion": 2.2e-05, | ||||
|             "gamma": 0.000843, | ||||
|             "pmd_coef": 1.265e-15 | ||||
|             } | ||||
|       ], | ||||
|       "RamanFiber":[ | ||||
|             { | ||||
|             "type_variety": "SSMF", | ||||
|             "dispersion": 1.67e-05, | ||||
|             "gamma": 0.00127, | ||||
|             "pmd_coef": 1.265e-15, | ||||
|             "raman_efficiency": { | ||||
|               "cr":[ | ||||
|                   0, 9.4E-06, 2.92E-05, 4.88E-05, 6.82E-05, 8.31E-05, 9.4E-05, 0.0001014, 0.0001069, 0.0001119, | ||||
|                   0.0001217, 0.0001268, 0.0001365, 0.000149, 0.000165, 0.000181, 0.0001977, 0.0002192, 0.0002469, | ||||
|                   0.0002749, 0.0002999, 0.0003206, 0.0003405, 0.0003592, 0.000374, 0.0003826, 0.0003841, 0.0003826, | ||||
|                   0.0003802, 0.0003756, 0.0003549, 0.0003795, 0.000344, 0.0002933, 0.0002024, 0.0001158, 8.46E-05, | ||||
|                   7.14E-05, 6.86E-05, 8.5E-05, 8.93E-05, 9.01E-05, 8.15E-05, 6.67E-05, 4.37E-05, 3.28E-05, 2.96E-05, | ||||
|                   2.65E-05, 2.57E-05, 2.81E-05, 3.08E-05, 3.67E-05, 5.85E-05, 6.63E-05, 6.36E-05, 5.5E-05, 4.06E-05, | ||||
|                   2.77E-05, 2.42E-05, 1.87E-05, 1.6E-05, 1.4E-05, 1.13E-05, 1.05E-05, 9.8E-06, 9.8E-06, 1.13E-05, | ||||
|                   1.64E-05, 1.95E-05, 2.38E-05, 2.26E-05, 2.03E-05, 1.48E-05, 1.09E-05, 9.8E-06, 1.05E-05, 1.17E-05, | ||||
|                   1.25E-05, 1.21E-05, 1.09E-05, 9.8E-06, 8.2E-06, 6.6E-06, 4.7E-06, 2.7E-06, 1.9E-06, 1.2E-06, 4E-07, | ||||
|                   2E-07, 1E-07 | ||||
|               ], | ||||
|               "frequency_offset":[ | ||||
|                 0, 0.5e12, 1e12, 1.5e12, 2e12, 2.5e12, 3e12, 3.5e12, 4e12, 4.5e12, 5e12, 5.5e12, 6e12, 6.5e12, 7e12, | ||||
|                 7.5e12, 8e12, 8.5e12, 9e12, 9.5e12, 10e12, 10.5e12, 11e12, 11.5e12, 12e12, 12.5e12, 12.75e12, | ||||
|                 13e12, 13.25e12, 13.5e12, 14e12, 14.5e12, 14.75e12, 15e12, 15.5e12, 16e12, 16.5e12, 17e12, | ||||
|                 17.5e12, 18e12, 18.25e12, 18.5e12, 18.75e12, 19e12, 19.5e12, 20e12, 20.5e12, 21e12, 21.5e12, | ||||
|                 22e12, 22.5e12, 23e12, 23.5e12, 24e12, 24.5e12, 25e12, 25.5e12, 26e12, 26.5e12, 27e12, 27.5e12, 28e12, | ||||
|                 28.5e12, 29e12, 29.5e12, 30e12, 30.5e12, 31e12, 31.5e12, 32e12, 32.5e12, 33e12, 33.5e12, 34e12, 34.5e12, | ||||
|                 35e12, 35.5e12, 36e12, 36.5e12, 37e12, 37.5e12, 38e12, 38.5e12, 39e12, 39.5e12, 40e12, 40.5e12, 41e12, | ||||
|                 41.5e12, 42e12 | ||||
|               ] | ||||
|               } | ||||
|             } | ||||
|       ], | ||||
|       "Span":[ | ||||
|             { | ||||
|             "power_mode":true, | ||||
|             "delta_power_range_db": [0,0,0], | ||||
|             "max_fiber_lineic_loss_for_raman": 0.25, | ||||
|             "target_extended_gain": 0, | ||||
|             "max_length": 135, | ||||
|             "length_units": "km", | ||||
|             "max_loss": 28, | ||||
|             "padding": 11, | ||||
|             "EOL": 0, | ||||
|             "con_in": 0, | ||||
|             "con_out": 0 | ||||
|             } | ||||
|       ], | ||||
|       "Roadm":[ | ||||
|             { | ||||
|             "target_pch_out_db": -20, | ||||
|             "add_drop_osnr": 33, | ||||
|             "pmd": 0, | ||||
|             "restrictions": { | ||||
|                             "preamp_variety_list":["openroadm_mw_mw_preamp_worstcase_ver5"], | ||||
|                             "booster_variety_list":["openroadm_mw_mw_booster"] | ||||
|                             }             | ||||
|             } | ||||
|       ], | ||||
|       "SI":[ | ||||
|             { | ||||
|             "f_min": 191.3e12, | ||||
|             "baud_rate": 31.57e9, | ||||
|             "f_max":196.1e12, | ||||
|             "spacing": 50e9, | ||||
|             "power_dbm": 2, | ||||
|             "power_range_db": [0,0,1], | ||||
|             "roll_off": 0.15, | ||||
|             "tx_osnr": 35, | ||||
|             "sys_margins": 2 | ||||
|             } | ||||
|       ], | ||||
|       "Transceiver":[ | ||||
| 		{ | ||||
|             "type_variety": "OpenROADM MSA ver. 5.0", | ||||
|             "frequency":{ | ||||
|                         "min": 191.35e12, | ||||
|                         "max": 196.1e12 | ||||
|                         }, | ||||
|             "mode":[ | ||||
|                         { | ||||
|                         "format": "100 Gbit/s, 27.95 Gbaud, DP-QPSK", | ||||
|                         "baud_rate": 27.95e9, | ||||
|                         "OSNR": 17, | ||||
|                         "bit_rate": 100e9, | ||||
|                         "roll_off": null, | ||||
|                         "tx_osnr": 33, | ||||
|                         "min_spacing": 50e9, | ||||
|                         "cost":1 | ||||
|                         }, | ||||
|                         { | ||||
|                         "format": "100 Gbit/s, 31.57 Gbaud, DP-QPSK", | ||||
|                         "baud_rate": 31.57e9, | ||||
|                         "OSNR": 12, | ||||
|                         "bit_rate": 100e9, | ||||
|                         "roll_off": 0.15, | ||||
|                         "tx_osnr": 36, | ||||
|                         "min_spacing": 50e9, | ||||
|                         "cost":1 | ||||
|                         }, | ||||
|                         { | ||||
|                         "format": "200 Gbit/s, 31.57 Gbaud, DP-16QAM", | ||||
|                         "baud_rate": 31.57e9, | ||||
|                         "OSNR": 20.5, | ||||
|                         "bit_rate": 100e9, | ||||
|                         "roll_off": 0.15, | ||||
|                         "tx_osnr": 36, | ||||
|                         "min_spacing": 50e9, | ||||
|                         "cost":1 | ||||
|                         }, | ||||
|                         { | ||||
|                         "format": "200 Gbit/s, DP-QPSK", | ||||
|                         "baud_rate": 63.1e9, | ||||
|                         "OSNR": 17, | ||||
|                         "bit_rate": 200e9, | ||||
|                         "roll_off": 0.15, | ||||
|                         "tx_osnr": 36, | ||||
|                         "min_spacing": 87.5e9, | ||||
|                         "cost":1 | ||||
|                         }, | ||||
|                         { | ||||
|                         "format": "300 Gbit/s, DP-8QAM", | ||||
|                         "baud_rate": 63.1e9, | ||||
|                         "OSNR": 21, | ||||
|                         "bit_rate": 300e9, | ||||
|                         "roll_off": 0.15, | ||||
|                         "tx_osnr": 36, | ||||
|                         "min_spacing": 87.5e9, | ||||
|                         "cost":1 | ||||
|                         }, | ||||
|                         { | ||||
|                         "format": "400 Gbit/s, DP-16QAM", | ||||
|                         "baud_rate": 63.1e9, | ||||
|                         "OSNR": 24, | ||||
|                         "bit_rate": 400e9, | ||||
|                         "roll_off": 0.15, | ||||
|                         "tx_osnr": 36, | ||||
|                         "min_spacing": 87.5e9, | ||||
|                         "cost":1 | ||||
|                         } | ||||
|                         ] | ||||
|             } | ||||
|       ] | ||||
|  | ||||
| } | ||||
| @@ -14,8 +14,8 @@ | ||||
|           "trx_mode": null, | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -39,8 +39,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -104,8 +104,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -129,8 +129,8 @@ | ||||
|           "trx_mode": null, | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
| @@ -154,8 +154,8 @@ | ||||
|           "trx_mode": "mode 2", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
| @@ -179,8 +179,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -204,8 +204,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -229,8 +229,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
|   | ||||
| @@ -18,9 +18,9 @@ from gnpy.tools.json_io import load_equipment | ||||
| from gnpy.topology.request import jsontocsv | ||||
|  | ||||
|  | ||||
| parser = ArgumentParser(description='A function that writes json path results in an excel sheet.') | ||||
| parser.add_argument('filename', nargs='?', type=Path) | ||||
| parser.add_argument('output_filename', nargs='?', type=Path) | ||||
| parser = ArgumentParser(description='Converting JSON path results into a CSV') | ||||
| parser.add_argument('filename', type=Path) | ||||
| parser.add_argument('output_filename', type=Path) | ||||
| parser.add_argument('eqpt_filename', nargs='?', type=Path, default=Path(__file__).parent / 'eqpt_config.json') | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|   | ||||
| @@ -103,6 +103,9 @@ def _add_common_options(parser: argparse.ArgumentParser, network_default: Path): | ||||
|                         help='Save the final network as a JSON file') | ||||
|     parser.add_argument('--save-network-before-autodesign', type=Path, metavar=_help_fname_json, | ||||
|                         help='Dump the network into a JSON file prior to autodesign') | ||||
|     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.') | ||||
|  | ||||
|  | ||||
| def transmission_main_example(args=None): | ||||
| @@ -187,6 +190,7 @@ def transmission_main_example(args=None): | ||||
|     params['loose_list'] = ['strict'] | ||||
|     params['format'] = '' | ||||
|     params['path_bandwidth'] = 0 | ||||
|     params['effective_freq_slot'] = None | ||||
|     trx_params = trx_mode_params(equipment) | ||||
|     if args.power: | ||||
|         trx_params['power'] = db2lin(float(args.power)) * 1e-3 | ||||
| @@ -200,7 +204,7 @@ def transmission_main_example(args=None): | ||||
|     pref_ch_db = lin2db(req.power * 1e3)  # reference channel power / span (SL=20dB) | ||||
|     pref_total_db = pref_ch_db + lin2db(req.nb_channel)  # reference total power / span (SL=20dB) | ||||
|     try: | ||||
|         build_network(network, equipment, pref_ch_db, pref_total_db) | ||||
|         build_network(network, equipment, pref_ch_db, pref_total_db, args.no_insert_edfas) | ||||
|     except exceptions.NetworkTopologyError as e: | ||||
|         print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') | ||||
|         sys.exit(1) | ||||
| @@ -214,17 +218,16 @@ def transmission_main_example(args=None): | ||||
|           f'and {destination.uid}') | ||||
|     print(f'\nNow propagating between {source.uid} and {destination.uid}:') | ||||
|  | ||||
|     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]') | ||||
|         power_range = [0] | ||||
|  | ||||
|     if not power_mode: | ||||
|     power_range = [0] | ||||
|     if power_mode: | ||||
|         # power cannot be changed in gain mode | ||||
|         power_range = [0] | ||||
|         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]') | ||||
|  | ||||
|     for dp_db in power_range: | ||||
|         req.power = db2lin(pref_ch_db + dp_db) * 1e-3 | ||||
|         if power_mode: | ||||
| @@ -307,7 +310,6 @@ def path_requests_run(args=None): | ||||
|     _setup_logging(args) | ||||
|  | ||||
|     _logger.info(f'Computing path requests {args.service_filename} into JSON format') | ||||
|     print(f'{ansi_escapes.blue}Computing path requests {os.path.relpath(args.service_filename)} into JSON format{ansi_escapes.reset}') | ||||
|  | ||||
|     (equipment, network) = load_common_data(args.equipment, args.topology, args.sim_params, args.save_network_before_autodesign) | ||||
|  | ||||
| @@ -319,7 +321,7 @@ def path_requests_run(args=None): | ||||
|     p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min, | ||||
|                                              equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) | ||||
|     try: | ||||
|         build_network(network, equipment, p_db, p_total_db) | ||||
|         build_network(network, equipment, p_db, p_total_db, args.no_insert_edfas) | ||||
|     except exceptions.NetworkTopologyError as e: | ||||
|         print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') | ||||
|         sys.exit(1) | ||||
|   | ||||
| @@ -18,7 +18,7 @@ from gnpy.core.equipment import trx_mode_params | ||||
| from gnpy.core.exceptions import ConfigurationError, EquipmentConfigError, NetworkTopologyError, ServiceError | ||||
| from gnpy.core.science_utils import estimate_nf_model | ||||
| from gnpy.core.utils import automatic_nch, automatic_fmax, merge_amplifier_restrictions | ||||
| from gnpy.topology.request import PathRequest, Disjunction | ||||
| from gnpy.topology.request import PathRequest, Disjunction, compute_spectrum_slot_vs_bandwidth | ||||
| from gnpy.tools.convert import xls_to_json_data | ||||
| from gnpy.tools.service_sheet import read_service_sheet | ||||
|  | ||||
| @@ -33,6 +33,14 @@ Model_hybrid = namedtuple('Model_hybrid', 'nf_ram gain_ram edfa_variety') | ||||
| Model_dual_stage = namedtuple('Model_dual_stage', 'preamp_variety booster_variety') | ||||
|  | ||||
|  | ||||
| class Model_openroadm_preamp: | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class Model_openroadm_booster: | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class _JsonThing: | ||||
|     def update_attr(self, default_values, kwargs, name): | ||||
|         clean_kwargs = {k: v for k, v in kwargs.items() if v != ''} | ||||
| @@ -201,8 +209,10 @@ class Amp(_JsonThing): | ||||
|             except KeyError:  # nf_coef is expected for openroadm amp | ||||
|                 raise EquipmentConfigError(f'missing nf_coef input for amplifier: {type_variety} in equipment config') | ||||
|             nf_def = Model_openroadm_ila(nf_coef) | ||||
|         elif type_def in ('openroadm_preamp', 'openroadm_booster'): | ||||
|             pass  # no extra parameters needed | ||||
|         elif type_def == 'openroadm_preamp': | ||||
|             nf_def = Model_openroadm_preamp() | ||||
|         elif type_def == 'openroadm_booster': | ||||
|             nf_def = Model_openroadm_booster() | ||||
|         elif type_def == 'dual_stage': | ||||
|             try:  # nf_ram and gain_ram are expected for a hybrid amp | ||||
|                 preamp_variety = kwargs.pop('preamp_variety') | ||||
| @@ -475,12 +485,12 @@ def requests_from_json(json_data, equipment): | ||||
|                 params['nb_channel'] = automatic_nch(f_min, f_max_from_si, params['spacing']) | ||||
|         except KeyError: | ||||
|             params['nb_channel'] = automatic_nch(f_min, f_max_from_si, params['spacing']) | ||||
|         _check_one_request(params, f_max_from_si) | ||||
|  | ||||
|         params['effective_freq_slot'] = req['path-constraints']['te-bandwidth'].get('effective-freq-slot', [None])[0] | ||||
|         try: | ||||
|             params['path_bandwidth'] = req['path-constraints']['te-bandwidth']['path_bandwidth'] | ||||
|         except KeyError: | ||||
|             pass | ||||
|         _check_one_request(params, f_max_from_si) | ||||
|         requests_list.append(PathRequest(**params)) | ||||
|     return requests_list | ||||
|  | ||||
| @@ -506,6 +516,22 @@ def _check_one_request(params, f_max_from_si): | ||||
|             max recommanded nb of channels is {max_recommanded_nb_channels}.''' | ||||
|             _logger.critical(msg) | ||||
|             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 \ | ||||
|             and params['effective_freq_slot']['M'] is not None: | ||||
|         _, requested_m = compute_spectrum_slot_vs_bandwidth(params['path_bandwidth'], | ||||
|                                                             params['spacing'], | ||||
|                                                             params['bit_rate']) | ||||
|         # params['effective_freq_slot']['M'] value should be bigger than the computed requested_m (simple estimate) | ||||
|         # TODO: elaborate a more accurate estimate with nb_wl * tx_osnr + possibly guardbands in case of | ||||
|         # superchannel closed packing. | ||||
|  | ||||
|         if requested_m > params['effective_freq_slot']['M']: | ||||
|             msg = f'requested M {params["effective_freq_slot"]["M"]} number of slots for request' +\ | ||||
|                   f'{params["request_id"]} should be greater than {requested_m} to support request' +\ | ||||
|                   f'{params["path_bandwidth"] * 1e-9} Gbit/s with {params["trx_type"]} {params["trx_mode"]}' | ||||
|             _logger.critical(msg) | ||||
|             raise ServiceError(msg) | ||||
|  | ||||
|  | ||||
| def disjunctions_from_json(json_data): | ||||
|   | ||||
| @@ -127,7 +127,7 @@ class Request_element(Element): | ||||
|                     'technology': 'flexi-grid', | ||||
|                     'trx_type': self.trx_type, | ||||
|                     'trx_mode': self.mode, | ||||
|                     'effective-freq-slot': [{'N': 'null', 'M': 'null'}], | ||||
|                     'effective-freq-slot': [{'N': None, 'M': None}], | ||||
|                     'spacing': self.spacing, | ||||
|                     'max-nb-of-channel': self.nb_channel, | ||||
|                     'output-power': self.power | ||||
|   | ||||
| @@ -35,7 +35,7 @@ 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 bit_rate roll_off tx_osnr' + | ||||
|                            ' min_spacing cost path_bandwidth') | ||||
|                            ' min_spacing cost path_bandwidth effective_freq_slot') | ||||
| DisjunctionParams = namedtuple('DisjunctionParams', 'disjunction_id relaxable link' + | ||||
|                                '_diverse node_diverse disjunctions_req') | ||||
|  | ||||
| @@ -68,6 +68,9 @@ class PathRequest: | ||||
|         self.min_spacing = params.min_spacing | ||||
|         self.cost = params.cost | ||||
|         self.path_bandwidth = params.path_bandwidth | ||||
|         if params.effective_freq_slot is not None: | ||||
|             self.N = params.effective_freq_slot['N'] | ||||
|             self.M = params.effective_freq_slot['M'] | ||||
|  | ||||
|     def __str__(self): | ||||
|         return '\n\t'.join([f'{type(self).__name__} {self.request_id}', | ||||
| @@ -75,7 +78,7 @@ class PathRequest: | ||||
|                             f'destination:  {self.destination}']) | ||||
|  | ||||
|     def __repr__(self): | ||||
|         if self.baud_rate is not None: | ||||
|         if self.baud_rate is not None and self.bit_rate is not None: | ||||
|             temp = self.baud_rate * 1e-9 | ||||
|             temp2 = self.bit_rate * 1e-9 | ||||
|         else: | ||||
| @@ -129,7 +132,7 @@ BLOCKING_NOPATH = ['NO_PATH', 'NO_PATH_WITH_CONSTRAINT', | ||||
|                    'NO_FEASIBLE_BAUDRATE_WITH_SPACING', | ||||
|                    'NO_COMPUTED_SNR'] | ||||
| BLOCKING_NOMODE = ['NO_FEASIBLE_MODE', 'MODE_NOT_FEASIBLE'] | ||||
| BLOCKING_NOSPECTRUM = 'NO_SPECTRUM' | ||||
| BLOCKING_NOSPECTRUM = ['NO_SPECTRUM', 'NOT_ENOUGH_RESERVED_SPECTRUM'] | ||||
|  | ||||
|  | ||||
| class ResultElement: | ||||
| @@ -162,7 +165,11 @@ class ResultElement: | ||||
|             } | ||||
|             pro_list.append(temp) | ||||
|             index += 1 | ||||
|             if self.path_request.M > 0: | ||||
|             if not hasattr(self.path_request, 'blocking_reason'): | ||||
|                 # M and N values should not be None at this point | ||||
|                 if self.path_request.M is None or self.path_request.N is None: | ||||
|                     raise ServiceError('request {self.path_id} should have positive non null n and m values.') | ||||
|  | ||||
|                 temp = { | ||||
|                     'path-route-object': { | ||||
|                         'index': index, | ||||
| @@ -174,12 +181,14 @@ class ResultElement: | ||||
|                 } | ||||
|                 pro_list.append(temp) | ||||
|                 index += 1 | ||||
|             elif self.path_request.M == 0 and hasattr(self.path_request, 'blocking_reason'): | ||||
|                 # if the path is blocked due to spectrum, no label object is created, but | ||||
|                 # the json response includes a detailed path for user infromation. | ||||
|                 pass | ||||
|             else: | ||||
|                 raise ServiceError('request {self.path_id} should have positive path bandwidth value.') | ||||
|                 # if the path is blocked, no label object is created, but | ||||
|                 # the json response includes a detailed path for user information. | ||||
|                 # M and N values should be None at this point | ||||
|                 if self.path_request.M is not None or self.path_request.N is not None: | ||||
|                     raise ServiceError('request {self.path_id} should not have label M and N values at this point.') | ||||
|  | ||||
|  | ||||
|             if isinstance(element, Transceiver): | ||||
|                 temp = { | ||||
|                     'path-route-object': { | ||||
| @@ -389,7 +398,6 @@ def propagate_and_optimize_mode(path, req, equipment): | ||||
|                 else: | ||||
|                     req.blocking_reason = 'NO_COMPUTED_SNR' | ||||
|                     return path, None | ||||
|  | ||||
|         # only get to this point if no baudrate/mode satisfies OSNR requirement | ||||
|  | ||||
|         # returns the last propagated path and mode | ||||
| @@ -696,8 +704,8 @@ def compute_path_dsjctn(network, equipment, pathreqlist, disjunctions_list): | ||||
|         # in each loop, dpath is updated with a path for rq that satisfies | ||||
|         # disjunction with each path in dpath | ||||
|         # for example, assume set of requests in the vector (disjunction_list) is  {rq1,rq2, rq3} | ||||
|         # rq1  p1: abfhg | ||||
|         #      p2: aefhg | ||||
|         # rq1  p1: aefhg | ||||
|         #      p2: abfhg | ||||
|         #      p3: abcg | ||||
|         # rq2  p8: bf | ||||
|         # rq3  p4: abcgh | ||||
| @@ -714,6 +722,7 @@ def compute_path_dsjctn(network, equipment, pathreqlist, disjunctions_list): | ||||
|         #  after second loop: | ||||
|         #  dpath = [ p3 p8 p6 ] | ||||
|         #  since p1 and p4 are not disjoint | ||||
|         #        p1 and p6 are not disjoint | ||||
|         #        p1 and p7 are not disjoint | ||||
|         #        p3 and p4 are not disjoint | ||||
|         #        p3 and p7 are not disjoint | ||||
| @@ -737,7 +746,6 @@ def compute_path_dsjctn(network, equipment, pathreqlist, disjunctions_list): | ||||
|                         temp.append(temp2) | ||||
|                         # print(f' coucou {elem1}: \t{temp}') | ||||
|             dpath = temp | ||||
|         # print(dpath) | ||||
|         candidates[dis.disjunction_id] = dpath | ||||
|  | ||||
|     # for i in disjunctions_list: | ||||
| @@ -778,9 +786,9 @@ def compute_path_dsjctn(network, equipment, pathreqlist, disjunctions_list): | ||||
|                         if pth in cndt: | ||||
|                             candidates[this_id].remove(cndt) | ||||
|  | ||||
| #    for i in disjunctions_list: | ||||
| #        print(i.disjunction_id) | ||||
| #        print(f'\n{candidates[i.disjunction_id]}') | ||||
|     # for i in disjunctions_list: | ||||
|     #     print(i.disjunction_id) | ||||
|     #     print(f'\n{candidates[i.disjunction_id]}') | ||||
|  | ||||
|     # step 4 apply route constraints: remove candidate path that do not satisfy | ||||
|     # the constraint only in  the case of disjounction: the simple path is processed in | ||||
| @@ -788,33 +796,34 @@ def compute_path_dsjctn(network, equipment, pathreqlist, disjunctions_list): | ||||
|     # TODO: keep a version without the loose constraint | ||||
|     for this_d in disjunctions_list: | ||||
|         temp = [] | ||||
|         alternatetemp = [] | ||||
|         for j, sol in enumerate(candidates[this_d.disjunction_id]): | ||||
|             testispartok = True | ||||
|             testispartnokloose = True | ||||
|             for pth in sol: | ||||
|                 # print(f'test {allpaths[id(pth)].req.request_id}') | ||||
|                 # print(f'length of route {len(allpaths[id(pth)].req.nodes_list)}') | ||||
|                 if allpaths[id(pth)].req.nodes_list: | ||||
|                     # if pth does not containt the ordered list node, remove sol from the candidate | ||||
|                     # except if this was the last solution: then check if the constraint is loose | ||||
|                     # or not | ||||
|                     # if any pth from sol does not contain the ordered list node, | ||||
|                     # remove sol from the candidate, except if constraint was loose: | ||||
|                     # then keep sol as an alternate solution | ||||
|                     if not ispart(allpaths[id(pth)].req.nodes_list, pth): | ||||
|                         # print(f'nb of solutions {len(temp)}') | ||||
|                         if j < len(candidates[this_d.disjunction_id]) - 1: | ||||
|                             msg = f'removing {sol}' | ||||
|                             LOGGER.info(msg) | ||||
|                             testispartok = False | ||||
|                             # break | ||||
|                         else: | ||||
|                             if 'LOOSE' in allpaths[id(pth)].req.loose_list: | ||||
|                                 LOGGER.info(f'Could not apply route constraint' + | ||||
|                                             f'{allpaths[id(pth)].req.nodes_list} on request' + | ||||
|                                             f' {allpaths[id(pth)].req.request_id}') | ||||
|                             else: | ||||
|                                 LOGGER.info(f'removing last solution from candidate paths\n{sol}') | ||||
|                                 testispartok = False | ||||
|                         testispartok = False | ||||
|                         if 'STRICT' in allpaths[id(pth)].req.loose_list: | ||||
|                             LOGGER.info(f'removing solution from candidate paths\n{pth}') | ||||
|                             testispartnokloose = False | ||||
|                             break | ||||
|             if testispartok: | ||||
|                 temp.append(sol) | ||||
|         candidates[this_d.disjunction_id] = temp | ||||
|             elif testispartnokloose: | ||||
|                 LOGGER.info(f'Adding solution as alternate solution not satisfying constraint\n{pth}') | ||||
|                 alternatetemp.append(sol) | ||||
|         if temp: | ||||
|             candidates[this_d.disjunction_id] = temp | ||||
|         elif alternatetemp: | ||||
|             candidates[this_d.disjunction_id] = alternatetemp | ||||
|         else: | ||||
|             candidates[this_d.disjunction_id] = [] | ||||
|  | ||||
|     # step 5 select the first combination that works | ||||
|     pathreslist_disjoint = {} | ||||
| @@ -964,7 +973,9 @@ def compare_reqs(req1, req2, disjlist): | ||||
|             req1.format == req2.format and \ | ||||
|             req1.OSNR == req2.OSNR and \ | ||||
|             req1.roll_off == req2.roll_off and \ | ||||
|             same_disj: | ||||
|             same_disj and \ | ||||
|             getattr(req1, 'N', None) is None and getattr(req2, 'N', None) is None and \ | ||||
|             getattr(req1, 'M', None) is None and getattr(req2, 'M', None) is None: | ||||
|         return True | ||||
|     else: | ||||
|         return False | ||||
| @@ -1152,7 +1163,8 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist): | ||||
|                     print(msg) | ||||
|                     LOGGER.warning(msg) | ||||
|                     # TODO selection of mode should also be on reversed direction !! | ||||
|                     pathreq.blocking_reason = 'MODE_NOT_FEASIBLE' | ||||
|                     if not hasattr(pathreq, 'blocking_reason'): | ||||
|                         pathreq.blocking_reason = 'MODE_NOT_FEASIBLE' | ||||
|             else: | ||||
|                 propagated_reversed_path = [] | ||||
|         else: | ||||
| @@ -1168,3 +1180,15 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist): | ||||
|         # print to have a nice output | ||||
|         print('') | ||||
|     return path_res_list, reversed_path_res_list, propagated_reversed_path_res_list | ||||
|  | ||||
|  | ||||
| def compute_spectrum_slot_vs_bandwidth(bandwidth, spacing, bit_rate, slot_width=0.0125e12): | ||||
|     """ Compute the number of required wavelengths and the M value (number of consumed slots) | ||||
|     Each wavelength consumes one `spacing`, and the result is rounded up to consume a natural number of slots. | ||||
|  | ||||
|     >>> compute_spectrum_slot_vs_bandwidth(400e9, 50e9, 200e9) | ||||
|     (2, 8) | ||||
|     """ | ||||
|     number_of_wavelengths = ceil(bandwidth / bit_rate) | ||||
|     total_number_of_slots = ceil(spacing / slot_width) * number_of_wavelengths | ||||
|     return number_of_wavelengths, total_number_of_slots | ||||
|   | ||||
| @@ -18,6 +18,7 @@ from logging import getLogger | ||||
| from math import ceil | ||||
| from gnpy.core.elements import Roadm, Transceiver | ||||
| from gnpy.core.exceptions import ServiceError, SpectrumError | ||||
| from gnpy.topology.request import compute_spectrum_slot_vs_bandwidth | ||||
|  | ||||
| LOGGER = getLogger(__name__) | ||||
|  | ||||
| @@ -390,42 +391,40 @@ def pth_assign_spectrum(pths, rqs, oms_list, rpths): | ||||
|     """ basic first fit assignment | ||||
|         if reversed path are provided, means that occupation is bidir | ||||
|     """ | ||||
|     for i, pth in enumerate(pths): | ||||
|     for pth, rq, rpth in zip(pths, rqs, rpths): | ||||
|         # computes the number of channels required | ||||
|         try: | ||||
|             if rqs[i].blocking_reason: | ||||
|                 rqs[i].blocked = True | ||||
|                 rqs[i].N = 0 | ||||
|                 rqs[i].M = 0 | ||||
|         except AttributeError: | ||||
|             nb_wl = ceil(rqs[i].path_bandwidth / rqs[i].bit_rate) | ||||
|             # computes the total nb of slots according to requested spacing | ||||
|             # TODO : express superchannels | ||||
|             # assumes that all channels must be grouped | ||||
|             # TODO : enables non contiguous reservation in case of blocking | ||||
|             requested_m = ceil(rqs[i].spacing / 0.0125e12) * nb_wl | ||||
|             # concatenate all path and reversed path elements to derive slots availability | ||||
|             (center_n, startn, stopn), path_oms = spectrum_selection(pth + rpths[i], oms_list, requested_m, | ||||
|                                                                      requested_n=None) | ||||
|             # checks that requested_m is fitting startm and stopm | ||||
|         if hasattr(rq, 'blocking_reason'): | ||||
|             rq.N = None | ||||
|             rq.M = None | ||||
|         else: | ||||
|             nb_wl, requested_m = compute_spectrum_slot_vs_bandwidth(rq.path_bandwidth, | ||||
|                                                                     rq.spacing, rq.bit_rate) | ||||
|             if getattr(rq, 'M', None) is not None: | ||||
|                 # Consistency check between the requested M and path_bandwidth | ||||
|                 # M value should be bigger than the computed requested_m (simple estimate) | ||||
|                 # TODO: elaborate a more accurate estimate with nb_wl * tx_osnr + possibly guardbands in case of | ||||
|                 # superchannel closed packing. | ||||
|                 if requested_m > rq.M: | ||||
|                     rq.N = None | ||||
|                     rq.M = None | ||||
|                     rq.blocking_reason = 'NOT_ENOUGH_RESERVED_SPECTRUM' | ||||
|                     # need to stop here for this request and not go though spectrum selection process with requested_m | ||||
|                     continue | ||||
|                 # use the req.M even if requested_m is smaller | ||||
|                 requested_m = rq.M | ||||
|             requested_n = getattr(rq, 'N', None) | ||||
|             (center_n, startn, stopn), path_oms = spectrum_selection(pth + rpth, oms_list, requested_m, | ||||
|                                                                      requested_n) | ||||
|             # if requested n and m concern already occupied spectrum the previous function returns a None candidate | ||||
|             # if not None, center_n and start, stop frequencies are applicable to all oms of pth | ||||
|             # checks that spectrum is not None else indicate blocking reason | ||||
|             if center_n is not None: | ||||
|                 # checks that requested_m is fitting startm and stopm | ||||
|                 if 2 * requested_m > (stopn - startn + 1): | ||||
|                     msg = f'candidate: {(center_n, startn, stopn)} is not consistant ' +\ | ||||
|                         f'with {requested_m}' | ||||
|                     LOGGER.critical(msg) | ||||
|                     raise ValueError(msg) | ||||
|  | ||||
|                 for oms_elem in path_oms: | ||||
|                     oms_list[oms_elem].assign_spectrum(center_n, requested_m) | ||||
|                     oms_list[oms_elem].add_service(rqs[i].request_id, nb_wl) | ||||
|                 rqs[i].blocked = False | ||||
|                 rqs[i].N = center_n | ||||
|                 rqs[i].M = requested_m | ||||
|                     oms_list[oms_elem].add_service(rq.request_id, nb_wl) | ||||
|                 rq.N = center_n | ||||
|                 rq.M = requested_m | ||||
|             else: | ||||
|                 rqs[i].blocked = True | ||||
|                 rqs[i].N = 0 | ||||
|                 rqs[i].M = 0 | ||||
|                 rqs[i].blocking_reason = 'NO_SPECTRUM' | ||||
|                 rq.N = None | ||||
|                 rq.M = None | ||||
|                 rq.blocking_reason = 'NO_SPECTRUM' | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| [metadata] | ||||
| name = gnpy | ||||
| description = Route planning and optimization tool for mesh optical networks | ||||
| description-file = README.rst | ||||
| description-content-type = text/x-rst; charset=UTF-8 | ||||
| description-file = README.md | ||||
| description-content-type = text/markdown; variant=GFM | ||||
| author = Telecom Infra Project | ||||
| author-email = jan.kundrat@telecominfraproject.com | ||||
| license = BSD-3-Clause | ||||
| @@ -10,7 +9,7 @@ home-page = https://github.com/Telecominfraproject/oopt-gnpy | ||||
| project_urls = | ||||
|     Bug Tracker = https://github.com/Telecominfraproject/oopt-gnpy/issues | ||||
|     Documentation = https://gnpy.readthedocs.io/ | ||||
| python-requires = >=3.6 | ||||
| python-requires = >=3.8 | ||||
| classifier = | ||||
|     Development Status :: 5 - Production/Stable | ||||
|     Intended Audience :: Developers | ||||
| @@ -20,8 +19,6 @@ classifier = | ||||
|     Natural Language :: English | ||||
|     Programming Language :: Python | ||||
|     Programming Language :: Python :: 3 :: Only | ||||
|     Programming Language :: Python :: 3.6 | ||||
|     Programming Language :: Python :: 3.7 | ||||
|     Programming Language :: Python :: 3.8 | ||||
|     Programming Language :: Python :: 3.9 | ||||
|     Programming Language :: Python :: Implementation :: CPython | ||||
|   | ||||
| @@ -14,8 +14,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -39,8 +39,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -64,8 +64,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|   | ||||
| @@ -14,8 +14,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -39,8 +39,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -104,8 +104,8 @@ | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
| @@ -129,8 +129,8 @@ | ||||
|           "trx_mode": "mode 2", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
| @@ -154,8 +154,8 @@ | ||||
|           "trx_mode": "mode 2", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
| @@ -179,8 +179,8 @@ | ||||
|           "trx_mode": "mode 2", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "N": "null", | ||||
|               "M": "null" | ||||
|               "N": null, | ||||
|               "M": null | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
|   | ||||
| @@ -12,12 +12,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager_16QAM", | ||||
|           "trx_mode": "16QAM", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": 0.001, | ||||
| @@ -37,12 +31,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "vendorA_trx-type1", | ||||
|           "trx_mode": "PS_SP64_1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": 0.001, | ||||
| @@ -62,12 +50,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "vendorA_trx-type1", | ||||
|           "trx_mode": "PS_SP64_1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": 0.001, | ||||
| @@ -87,12 +69,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "vendorA_trx-type1", | ||||
|           "trx_mode": "PS_SP64_1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": 0.001, | ||||
| @@ -133,12 +109,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": "mode 2 - fake", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
|           "max-nb-of-channel": 63, | ||||
|           "output-power": 0.001, | ||||
| @@ -158,12 +128,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": "mode 2", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
|           "max-nb-of-channel": 63, | ||||
|           "output-power": 0.001, | ||||
| @@ -183,12 +147,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "vendorA_trx-type1", | ||||
|           "trx_mode": "PS_SP64_1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": 0.001, | ||||
| @@ -221,12 +179,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": "mode 3", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 62500000000.0, | ||||
|           "max-nb-of-channel": 76, | ||||
|           "output-power": 0.001, | ||||
| @@ -259,12 +211,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "vendorA_trx-type1", | ||||
|           "trx_mode": "PS_SP64_1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": 0.001, | ||||
| @@ -284,12 +230,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "vendorA_trx-type1", | ||||
|           "trx_mode": "PS_SP64_1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": 0.001, | ||||
| @@ -330,12 +270,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager_16QAM", | ||||
|           "trx_mode": "16QAM", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": null, | ||||
| @@ -355,12 +289,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": "mode 1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": null, | ||||
|           "output-power": 0.001, | ||||
| @@ -380,12 +308,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "vendorA_trx-type1", | ||||
|           "trx_mode": "PS_SP64_1", | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": null, | ||||
|           "output-power": null, | ||||
| @@ -405,12 +327,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "vendorA_trx-type1", | ||||
|           "trx_mode": null, | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": 80, | ||||
|           "output-power": 0.001, | ||||
| @@ -451,12 +367,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": null, | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": null, | ||||
|           "output-power": 0.001, | ||||
| @@ -476,12 +386,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": null, | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
|           "max-nb-of-channel": 63, | ||||
|           "output-power": null, | ||||
| @@ -501,12 +405,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": null, | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 50000000000.0, | ||||
|           "max-nb-of-channel": null, | ||||
|           "output-power": null, | ||||
| @@ -526,12 +424,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": null, | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 75000000000.0, | ||||
|           "max-nb-of-channel": null, | ||||
|           "output-power": null, | ||||
| @@ -551,12 +443,6 @@ | ||||
|           "technology": "flexi-grid", | ||||
|           "trx_type": "Voyager", | ||||
|           "trx_mode": null, | ||||
|           "effective-freq-slot": [ | ||||
|             { | ||||
|               "n": "null", | ||||
|               "m": "null" | ||||
|             } | ||||
|           ], | ||||
|           "spacing": 30000000000.0, | ||||
|           "max-nb-of-channel": null, | ||||
|           "output-power": null, | ||||
|   | ||||
							
								
								
									
										239
									
								
								tests/invocation/openroadm-v5-Stockholm-Gothenburg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								tests/invocation/openroadm-v5-Stockholm-Gothenburg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,239 @@ | ||||
| There are 96 channels propagating | ||||
| Power mode is set to True | ||||
| => it can be modified in eqpt_config.json - Span | ||||
|  | ||||
| There are 6 fiber spans over 500 km between trx_Stockholm and trx_Gothenburg | ||||
|  | ||||
| Now propagating between trx_Stockholm and trx_Gothenburg: | ||||
|  | ||||
| Propagating with input power = [1;36;40m2.00 dBm[0m: | ||||
| Transceiver trx_Stockholm | ||||
|   GSNR (0.1nm, dB):          35.00 | ||||
|   GSNR (signal bw, dB):      30.98 | ||||
|   OSNR ASE (0.1nm, dB):      35.00 | ||||
|   OSNR ASE (signal bw, dB):  30.98 | ||||
|   CD (ps/nm):                0.00 | ||||
|   PMD (ps):                  0.00 | ||||
| Roadm roadm_Stockholm | ||||
|   effective loss (dB):  22.00 | ||||
|   pch out (dBm):        -20.00 | ||||
| Edfa Edfa_booster_roadm_Stockholm_to_fiber (Stockholm → Norrköping)_(1/2) | ||||
|   type_variety:           openroadm_mw_mw_booster | ||||
|   effective gain(dB):     22.00 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      -inf | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         -0.18 | ||||
|   Power Out (dBm):        21.82 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Fiber          fiber (Stockholm → Norrköping)_(1/2) | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 81.63 | ||||
|   pad att_in (dB):             0.00 | ||||
|   total loss (dB):             16.33 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -14.33 | ||||
| Edfa Edfa_fiber (Stockholm → Norrköping)_(1/2) | ||||
|   type_variety:           openroadm_ila_low_noise | ||||
|   effective gain(dB):     16.33 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      8.01 | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         5.51 | ||||
|   Power Out (dBm):        21.84 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Fiber          fiber (Stockholm → Norrköping)_(2/2) | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 81.63 | ||||
|   pad att_in (dB):             0.00 | ||||
|   total loss (dB):             16.33 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -14.33 | ||||
| Edfa Edfa_preamp_roadm_Norrköping_from_fiber (Stockholm → Norrköping)_(2/2) | ||||
|   type_variety:           openroadm_mw_mw_preamp_worstcase_ver5 | ||||
|   effective gain(dB):     16.33 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      11.44 | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         5.53 | ||||
|   Power Out (dBm):        21.86 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Roadm roadm_Norrköping | ||||
|   effective loss (dB):  22.00 | ||||
|   pch out (dBm):        -20.00 | ||||
| Edfa Edfa_booster_roadm_Norrköping_to_fiber (Norrköping → Linköping) | ||||
|   type_variety:           openroadm_mw_mw_booster | ||||
|   effective gain(dB):     22.00 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      -inf | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         -0.18 | ||||
|   Power Out (dBm):        21.82 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Fiber          fiber (Norrköping → Linköping) | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 45.99 | ||||
|   pad att_in (dB):             1.80 | ||||
|   total loss (dB):             11.00 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -9.00 | ||||
| Edfa Edfa_preamp_roadm_Linköping_from_fiber (Norrköping → Linköping) | ||||
|   type_variety:           openroadm_mw_mw_preamp_worstcase_ver5 | ||||
|   effective gain(dB):     11.00 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      16.00 | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         10.83 | ||||
|   Power Out (dBm):        21.83 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Roadm roadm_Linköping | ||||
|   effective loss (dB):  22.00 | ||||
|   pch out (dBm):        -20.00 | ||||
| Edfa Edfa_booster_roadm_Linköping_to_fiber (Linköping → Jönköping) | ||||
|   type_variety:           openroadm_mw_mw_booster | ||||
|   effective gain(dB):     22.00 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      -inf | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         -0.18 | ||||
|   Power Out (dBm):        21.82 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Fiber          fiber (Linköping → Jönköping) | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 134.02 | ||||
|   pad att_in (dB):             0.00 | ||||
|   total loss (dB):             26.80 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -24.80 | ||||
| Edfa Edfa_preamp_roadm_Jönköping_from_fiber (Linköping → Jönköping) | ||||
|   type_variety:           openroadm_mw_mw_preamp_worstcase_ver5 | ||||
|   effective gain(dB):     26.80 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      8.01 | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         -4.97 | ||||
|   Power Out (dBm):        21.86 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Roadm roadm_Jönköping | ||||
|   effective loss (dB):  22.00 | ||||
|   pch out (dBm):        -20.00 | ||||
| Edfa Edfa_booster_roadm_Jönköping_to_fiber (Jönköping → Borås) | ||||
|   type_variety:           openroadm_mw_mw_booster | ||||
|   effective gain(dB):     22.00 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      -inf | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         -0.18 | ||||
|   Power Out (dBm):        21.82 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Fiber          fiber (Jönköping → Borås) | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 89.12 | ||||
|   pad att_in (dB):             0.00 | ||||
|   total loss (dB):             17.82 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -15.82 | ||||
| Edfa Edfa_preamp_roadm_Borås_from_fiber (Jönköping → Borås) | ||||
|   type_variety:           openroadm_mw_mw_preamp_worstcase_ver5 | ||||
|   effective gain(dB):     17.82 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      10.54 | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         4.01 | ||||
|   Power Out (dBm):        21.84 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Roadm roadm_Borås | ||||
|   effective loss (dB):  22.00 | ||||
|   pch out (dBm):        -20.00 | ||||
| Edfa Edfa_booster_roadm_Borås_to_fiber (Borås → Gothenburg) | ||||
|   type_variety:           openroadm_mw_mw_booster | ||||
|   effective gain(dB):     22.00 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      -inf | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         -0.18 | ||||
|   Power Out (dBm):        21.82 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Fiber          fiber (Borås → Gothenburg) | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 67.64 | ||||
|   pad att_in (dB):             0.00 | ||||
|   total loss (dB):             13.53 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -11.53 | ||||
| Edfa Edfa_preamp_roadm_Gothenburg_from_fiber (Borås → Gothenburg) | ||||
|   type_variety:           openroadm_mw_mw_preamp_worstcase_ver5 | ||||
|   effective gain(dB):     13.53 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      13.54 | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         8.30 | ||||
|   Power Out (dBm):        21.84 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       2.00 | ||||
|   effective pch (dBm):    2.00 | ||||
|   output VOA (dB):        0.00 | ||||
| Roadm roadm_Gothenburg | ||||
|   effective loss (dB):  22.00 | ||||
|   pch out (dBm):        -20.00 | ||||
| Transceiver trx_Gothenburg | ||||
|   GSNR (0.1nm, dB):          19.27 | ||||
|   GSNR (signal bw, dB):      15.24 | ||||
|   OSNR ASE (0.1nm, dB):      21.84 | ||||
|   OSNR ASE (signal bw, dB):  17.82 | ||||
|   CD (ps/nm):                8350.42 | ||||
|   PMD (ps):                  0.89 | ||||
|  | ||||
| Transmission result for input power = 2.00 dBm: | ||||
|   Final GSNR (0.1 nm): [1;36;40m19.27 dB[0m | ||||
|  | ||||
| (No source node specified: picked trx_Stockholm) | ||||
|  | ||||
| (No destination node specified: picked trx_Gothenburg) | ||||
| @@ -1,4 +1,3 @@ | ||||
| [1;34;40mComputing path requests gnpy/example-data/meshTopologyExampleV2.xls into JSON format[0m | ||||
| [1;34;40mList of disjunctions[0m | ||||
| [Disjunction 3 | ||||
| 	relaxable:    false | ||||
|   | ||||
							
								
								
									
										326
									
								
								tests/invocation/transmission_saturated
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								tests/invocation/transmission_saturated
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,326 @@ | ||||
| There are 96 channels propagating | ||||
| Power mode is set to True | ||||
| => it can be modified in eqpt_config.json - Span | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Lorient_KMA to Loudeac | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING[0m: WARNING: effective gain in Node east edfa in Lannion_CAS to Stbrieuc is above user specified amplifier std_low_gain | ||||
| max flat gain: 16dB ; required gain: 23.0dB. Please check amplifier type. | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Rennes_STA to Stbrieuc | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING[0m: WARNING: effective gain in Node east edfa in Lannion_CAS to Morlaix is above user specified amplifier std_low_gain | ||||
| max flat gain: 16dB ; required gain: 23.5dB. Please check amplifier type. | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Brest_KLA to Morlaix | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Lorient_KMA to Loudeac | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING[0m: WARNING: effective gain in Node west edfa in Lannion_CAS to Corlay is above user specified amplifier test | ||||
| max flat gain: 25dB ; required gain: 29.82dB. Please check amplifier type. | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Lorient_KMA to Vannes_KBE | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Vannes_KBE to Lorient_KMA | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Lorient_KMA to Quimper | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Quimper to Lorient_KMA | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Brest_KLA to Quimper | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Vannes_KBE to Lorient_KMA | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Lorient_KMA to Vannes_KBE | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Vannes_KBE to Ploermel | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Ploermel to Vannes_KBE | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Rennes_STA to Ploermel | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Rennes_STA to Stbrieuc | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Stbrieuc to Rennes_STA | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Lannion_CAS to Stbrieuc | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Rennes_STA to Ploermel | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Vannes_KBE to Ploermel | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Brest_KLA to Morlaix | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING[0m: WARNING: effective gain in Node east edfa in Brest_KLA to Quimper is above user specified amplifier std_low_gain | ||||
| max flat gain: 16dB ; required gain: 23.0dB. Please check amplifier type. | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in Quimper to Lorient_KMA | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in Lorient_KMA to Quimper | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in a to b | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in b to a | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in a to c | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in c to a | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in b to a | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in a to b | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in b to f | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in f to b | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in c to a | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in a to c | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in d to c | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in c to f | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in f to c | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in d to c | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in c to d | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in d to e | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in e to d | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in e to d | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in d to e | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in e to g | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in g to e | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in f to c | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in c to f | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in f to b | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in b to f | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in f to h | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in h to f | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in g to e | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in e to g | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in g to h | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in h to g | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in h to f | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in f to h | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node east edfa in h to g | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
| [1;31;40mWARNING:[0m target gain and power in node west edfa in g to h | ||||
|      is beyond all available amplifiers capabilities and/or extended_gain_range: | ||||
|     a power reduction of -1.82 is applied | ||||
|  | ||||
|  | ||||
| There are 3 fiber spans over 130 km between trx Lannion_CAS and trx Lorient_KMA | ||||
|  | ||||
| Now propagating between trx Lannion_CAS and trx Lorient_KMA: | ||||
|  | ||||
| Propagating with input power = [1;36;40m3.00 dBm[0m: | ||||
| Transceiver trx Lannion_CAS | ||||
|   GSNR (0.1nm, dB):          100.00 | ||||
|   GSNR (signal bw, dB):      95.92 | ||||
|   OSNR ASE (0.1nm, dB):      100.00 | ||||
|   OSNR ASE (signal bw, dB):  95.92 | ||||
|   CD (ps/nm):                0.00 | ||||
|   PMD (ps):                  0.00 | ||||
| Roadm roadm Lannion_CAS | ||||
|   effective loss (dB):  23.00 | ||||
|   pch out (dBm):        -20.00 | ||||
| Edfa east edfa in Lannion_CAS to Corlay | ||||
|   type_variety:           test | ||||
|   effective gain(dB):     21.18 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      6.13 | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         -0.18 | ||||
|   Power Out (dBm):        21.01 | ||||
|   Delta_P (dB):           0.00 | ||||
|   target pch (dBm):       3.00 | ||||
|   effective pch (dBm):    1.18 | ||||
|   output VOA (dB):        0.00 | ||||
| Fiber          fiber (Lannion_CAS → Corlay)-F061 | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 20.00 | ||||
|   pad att_in (dB):             0.00 | ||||
|   total loss (dB):             4.00 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -2.82 | ||||
| Fused west fused spans in Corlay | ||||
|   loss (dB): 1.00 | ||||
| Fiber          fiber (Corlay → Loudeac)-F010 | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 50.00 | ||||
|   pad att_in (dB):             0.00 | ||||
|   total loss (dB):             10.00 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -13.82 | ||||
| Fused west fused spans in Loudeac | ||||
|   loss (dB): 1.00 | ||||
| Fiber          fiber (Loudeac → Lorient_KMA)-F054 | ||||
|   type_variety:                SSMF | ||||
|   length (km):                 60.00 | ||||
|   pad att_in (dB):             0.00 | ||||
|   total loss (dB):             12.00 | ||||
|   (includes conn loss (dB) in: 0.00 out: 0.00) | ||||
|   (conn loss out includes EOL margin defined in eqpt_config.json) | ||||
|   pch out (dBm): -26.82 | ||||
| Edfa west edfa in Lorient_KMA to Loudeac | ||||
|   type_variety:           test | ||||
|   effective gain(dB):     28.00 | ||||
|   (before att_in and before output VOA) | ||||
|   noise figure (dB):      5.76 | ||||
|   (including att_in) | ||||
|   pad att_in (dB):        0.00 | ||||
|   Power In (dBm):         -6.99 | ||||
|   Power Out (dBm):        21.04 | ||||
|   Delta_P (dB):           -1.82 | ||||
|   target pch (dBm):       1.18 | ||||
|   effective pch (dBm):    1.18 | ||||
|   output VOA (dB):        0.00 | ||||
| Roadm roadm Lorient_KMA | ||||
|   effective loss (dB):  21.18 | ||||
|   pch out (dBm):        -20.00 | ||||
| Transceiver trx Lorient_KMA | ||||
|   GSNR (0.1nm, dB):          23.94 | ||||
|   GSNR (signal bw, dB):      19.85 | ||||
|   OSNR ASE (0.1nm, dB):      24.29 | ||||
|   OSNR ASE (signal bw, dB):  20.20 | ||||
|   CD (ps/nm):                2171.00 | ||||
|   PMD (ps):                  0.46 | ||||
|  | ||||
| Transmission result for input power = 3.00 dBm: | ||||
|   Final GSNR (0.1 nm): [1;36;40m23.94 dB[0m | ||||
|  | ||||
| (Invalid source node 'lannion' replaced with trx Lannion_CAS) | ||||
|  | ||||
| (Invalid destination node 'lorient' replaced with trx Lorient_KMA) | ||||
| @@ -4,18 +4,18 @@ | ||||
| # License: BSD 3-Clause Licence | ||||
| # Copyright (c) 2018, Telecom Infra Project | ||||
|  | ||||
| """ | ||||
| ''' | ||||
| @author: esther.lerouzic | ||||
| checks that computed paths are disjoint as specified in the json service file | ||||
| that computed paths do not loop | ||||
| that include node constraints are correctly taken into account | ||||
| """ | ||||
| ''' | ||||
|  | ||||
| from pathlib import Path | ||||
| import pytest | ||||
| from gnpy.core.equipment import trx_mode_params | ||||
| from gnpy.core.network import build_network | ||||
| from gnpy.core.exceptions import ServiceError | ||||
| from gnpy.core.exceptions import ServiceError, DisjunctionError | ||||
| from gnpy.core.utils import automatic_nch, lin2db | ||||
| from gnpy.core.elements import Roadm | ||||
| from gnpy.topology.request import (compute_path_dsjctn, isdisjoint, find_reversed_path, PathRequest, | ||||
| @@ -31,8 +31,8 @@ EQPT_LIBRARY_NAME = Path(__file__).parent.parent / 'tests/data/eqpt_config.json' | ||||
|  | ||||
| @pytest.fixture() | ||||
| def serv(test_setup): | ||||
|     """ common setup for service list | ||||
|     """ | ||||
|     ''' common setup for service list | ||||
|     ''' | ||||
|     network, equipment = test_setup | ||||
|     data = load_requests(SERVICE_FILE_NAME, equipment, bidir=False, network=network, network_filename=NETWORK_FILE_NAME) | ||||
|     rqs = requests_from_json(data, equipment) | ||||
| @@ -43,12 +43,12 @@ def serv(test_setup): | ||||
|  | ||||
| @pytest.fixture() | ||||
| def test_setup(): | ||||
|     """ common setup for tests: builds network, equipment and oms only once | ||||
|     """ | ||||
|     ''' common setup for tests: builds network, equipment and oms only once | ||||
|     ''' | ||||
|     equipment = load_equipment(EQPT_LIBRARY_NAME) | ||||
|     network = load_network(NETWORK_FILE_NAME, equipment) | ||||
|     # Build the network once using the default power defined in SI in eqpt config | ||||
|     # power density : db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by | ||||
|     # power density : db2linp(ower_dbm': 0)/power_dbm': 0 * nb channels as defined by | ||||
|     # spacing, f_min and f_max | ||||
|     p_db = equipment['SI']['default'].power_dbm | ||||
|  | ||||
| @@ -61,9 +61,9 @@ def test_setup(): | ||||
|  | ||||
|  | ||||
| def test_disjunction(serv): | ||||
|     """ service_file contains sevaral combination of disjunction constraint. The test checks | ||||
|     ''' service_file contains sevaral combination of disjunction constraint. The test checks | ||||
|         that computed paths with disjunction constraint are effectively disjoint | ||||
|     """ | ||||
|     ''' | ||||
|     network, equipment, rqs, dsjn = serv | ||||
|     pths = compute_path_dsjctn(network, equipment, rqs, dsjn) | ||||
|     print(dsjn) | ||||
| @@ -86,8 +86,8 @@ def test_disjunction(serv): | ||||
|  | ||||
|  | ||||
| def test_does_not_loop_back(serv): | ||||
|     """ check that computed paths do not loop back ie each element appears only once | ||||
|     """ | ||||
|     ''' check that computed paths do not loop back ie each element appears only once | ||||
|     ''' | ||||
|     network, equipment, rqs, dsjn = serv | ||||
|     pths = compute_path_dsjctn(network, equipment, rqs, dsjn) | ||||
|     test = True | ||||
| @@ -107,33 +107,35 @@ def test_does_not_loop_back(serv): | ||||
|     # | ||||
|  | ||||
|  | ||||
| def create_rq(equipment, srce, dest, bdir, nd_list, ls_list): | ||||
|     """ create the usual request list according to parameters | ||||
|     """ | ||||
| def create_rq(equipment, srce, dest, bdir, node_list, loose_list, rqid='test_request'): | ||||
|     ''' create the usual request list according to parameters | ||||
|     ''' | ||||
|     requests_list = [] | ||||
|     params = {} | ||||
|     params['request_id'] = 'test_request' | ||||
|     params['source'] = srce | ||||
|     params['bidir'] = bdir | ||||
|     params['destination'] = dest | ||||
|     params['trx_type'] = 'Voyager' | ||||
|     params['trx_mode'] = 'mode 1' | ||||
|     params = { | ||||
|         'request_id': rqid, | ||||
|         'source': srce, | ||||
|         'bidir': bdir, | ||||
|         'destination': dest, | ||||
|         'trx_type': 'Voyager', | ||||
|         'trx_mode': 'mode 1', | ||||
|         'spacing': 50000000000.0, | ||||
|         'nodes_list': node_list, | ||||
|         'loose_list': loose_list, | ||||
|         'path_bandwidth': 100.0e9, | ||||
|         'power': 1.0, | ||||
|         'effective_freq_slot': None, | ||||
|     } | ||||
|     params['format'] = params['trx_mode'] | ||||
|     params['spacing'] = 50000000000.0 | ||||
|     params['nodes_list'] = nd_list | ||||
|     params['loose_list'] = ls_list | ||||
|     trx_params = trx_mode_params(equipment, params['trx_type'], params['trx_mode'], True) | ||||
|     params.update(trx_params) | ||||
|     params['power'] = 1.0 | ||||
|     f_min = params['f_min'] | ||||
|     f_max_from_si = params['f_max'] | ||||
|     params['nb_channel'] = automatic_nch(f_min, f_max_from_si, params['spacing']) | ||||
|     params['path_bandwidth'] = 100000000000.0 | ||||
|     requests_list.append(PathRequest(**params)) | ||||
|     return requests_list | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize('srce, dest, result, pth, nd_list, ls_list', [ | ||||
| @pytest.mark.parametrize('srce, dest, result, pth, node_list, loose_list', [ | ||||
|     ['a', 'trx h', 'fail', 'no_path', [], []], | ||||
|     ['trx a', 'h', 'fail', 'no_path', [], []], | ||||
|     ['trx a', 'trx h', 'pass', 'found_path', [], []], | ||||
| @@ -148,8 +150,8 @@ def create_rq(equipment, srce, dest, bdir, nd_list, ls_list): | ||||
|     ['trx a', 'trx h', 'pass', 'found_path', ['trx a', 'roadm g'], ['STRICT', 'STRICT']], | ||||
|     ['trx a', 'trx h', 'pass', 'found_path', ['trx h'], ['STRICT']], | ||||
|     ['trx a', 'trx h', 'pass', 'found_path', ['roadm a'], ['STRICT']]]) | ||||
| def test_include_constraints(test_setup, srce, dest, result, pth, nd_list, ls_list): | ||||
|     """ check that all combinations of constraints are correctly handled: | ||||
| def test_include_constraints(test_setup, srce, dest, result, pth, node_list, loose_list): | ||||
|     ''' check that all combinations of constraints are correctly handled: | ||||
|         - STRICT/LOOSE | ||||
|         - correct names/incorrect names -> pass/fail | ||||
|         - possible include/impossible include | ||||
| @@ -161,20 +163,82 @@ def test_include_constraints(test_setup, srce, dest, result, pth, nd_list, ls_li | ||||
|                                 | cannot be applied | no_path           | found_path | ||||
|             ---------------------------------------------------------------------------------- | ||||
|             0                   |                   |          computation stops | ||||
|     """ | ||||
|     ''' | ||||
|     network, equipment = test_setup | ||||
|     dsjn = [] | ||||
|     bdir = False | ||||
|     rqs = create_rq(equipment, srce, dest, bdir, nd_list, ls_list) | ||||
|     rqs = create_rq(equipment, srce, dest, bdir, node_list, loose_list) | ||||
|     print(rqs) | ||||
|     if result == 'fail': | ||||
|         with pytest.raises(ServiceError): | ||||
|             rqs = correct_json_route_list(network, rqs) | ||||
|     else: | ||||
|         rqs = correct_json_route_list(network, rqs) | ||||
|         pths = compute_path_dsjctn(network, equipment, rqs, dsjn) | ||||
|         paths = compute_path_dsjctn(network, equipment, rqs, dsjn) | ||||
|         # if loose, one path can be returned | ||||
|         if pths[0]: | ||||
|         if paths[0]: | ||||
|             assert pth == 'found_path' | ||||
|         else: | ||||
|             assert pth == 'no_path' | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize('dis1, dis2, node_list1, loose_list1, result, expected_paths', [ | ||||
|     [['1', '2', '3'], ['2', '3'], [], [], 'pass', | ||||
|      [['roadm a', 'roadm c', 'roadm d', 'roadm e', 'roadm g'], | ||||
|       ['roadm c', 'roadm f'], | ||||
|       ['roadm a', 'roadm b', 'roadm f', 'roadm h']]], | ||||
|     [['1', '2', '3'], ['2', '3'], ['b'], ['STRICT'], 'fail', []], | ||||
|     [['1', '2'], ['2', '3'], [], [], 'pass', | ||||
|      [['roadm a', 'roadm c', 'roadm d', 'roadm e', 'roadm g'], | ||||
|       ['roadm c', 'roadm f'], | ||||
|       ['roadm a', 'roadm b', 'roadm f', 'roadm h']]], | ||||
|     [['1', '2'], ['2', '3'], ['roadm e'], ['LOOSE'], 'pass', | ||||
|      [['roadm a', 'roadm c', 'roadm d', 'roadm e', 'roadm g'], | ||||
|       ['roadm c', 'roadm f'], | ||||
|       ['roadm a', 'roadm b', 'roadm f', 'roadm h']]], | ||||
|     [['1', '2'], ['2', '3'], ['roadm c | roadm f'], ['LOOSE'], 'pass', | ||||
|      [['roadm a', 'roadm c', 'roadm d', 'roadm e', 'roadm g'], | ||||
|       ['roadm c', 'roadm f'], | ||||
|       ['roadm a', 'roadm b', 'roadm f', 'roadm h']]]]) | ||||
| def test_create_disjunction(test_setup, dis1, dis2, node_list1, loose_list1, result, expected_paths): | ||||
|     """ verifies that the expected result is obtained for a set of particular constraints: | ||||
|     in particular, verifies that: | ||||
|     - multiple disjunction constraints are correcly handled | ||||
|     - in case a loose constraint can not be met, the first alternate candidate is selected | ||||
|     instead of the last one (last case). | ||||
|     """ | ||||
|     network, equipment = test_setup | ||||
|  | ||||
|     json_data = { | ||||
|         'synchronization': [{ | ||||
|             'synchronization-id': 'x', | ||||
|             'svec': { | ||||
|                 'relaxable': 'false', | ||||
|                 'disjointness': 'node link', | ||||
|                 'request-id-number': dis1 | ||||
|             } | ||||
|         }, { | ||||
|             'synchronization-id': 'y', | ||||
|             'svec': { | ||||
|                 'relaxable': 'false', | ||||
|                 'disjointness': 'node link', | ||||
|                 'request-id-number': dis2 | ||||
|             } | ||||
|         }]} | ||||
|     dsjn = disjunctions_from_json(json_data) | ||||
|     bdir = False | ||||
|     rqs = create_rq(equipment, 'trx a', 'trx g', bdir, node_list1, loose_list1, '1') +\ | ||||
|         create_rq(equipment, 'trx c', 'trx f', bdir, [], [], '2') +\ | ||||
|         create_rq(equipment, 'trx a', 'trx h', bdir, [], [], '3') | ||||
|  | ||||
|     if result == 'fail': | ||||
|         with pytest.raises(DisjunctionError): | ||||
|             paths = compute_path_dsjctn(network, equipment, rqs, dsjn) | ||||
|     else: | ||||
|         paths = compute_path_dsjctn(network, equipment, rqs, dsjn) | ||||
|         path_names = [] | ||||
|         for path in paths: | ||||
|             roadm_names = [e.uid for e in path if isinstance(e, Roadm)] | ||||
|             path_names.append(roadm_names) | ||||
|         assert path_names == expected_paths | ||||
|         # if loose, one path can be returned | ||||
|   | ||||
| @@ -11,20 +11,24 @@ SRC_ROOT = Path(__file__).parent.parent | ||||
|  | ||||
| @pytest.mark.parametrize("output, handler, args", ( | ||||
|     ('transmission_main_example', transmission_main_example, []), | ||||
|     ('transmission_saturated', transmission_main_example, | ||||
|      ['tests/data/testTopology_expected.json', 'lannion', 'lorient', '-e', 'tests/data/eqpt_config.json', '--pow', '3']), | ||||
|     ('path_requests_run', path_requests_run, []), | ||||
|     ('transmission_main_example__raman', transmission_main_example, | ||||
|      ['gnpy/example-data/raman_edfa_example_network.json', '--sim', 'gnpy/example-data/sim_params.json', '--show-channels', ]), | ||||
|     ('openroadm-Stockholm-Gothenburg', transmission_main_example, | ||||
|      ['-e', 'gnpy/example-data/eqpt_config_openroadm.json', 'gnpy/example-data/Sweden_OpenROADM_example_network.json', ]), | ||||
|     ('openroadm-v4-Stockholm-Gothenburg', transmission_main_example, | ||||
|      ['-e', 'gnpy/example-data/eqpt_config_openroadm_ver4.json', 'gnpy/example-data/Sweden_OpenROADMv4_example_network.json', ]), | ||||
|     ('openroadm-v5-Stockholm-Gothenburg', transmission_main_example, | ||||
|      ['-e', 'gnpy/example-data/eqpt_config_openroadm_ver5.json', 'gnpy/example-data/Sweden_OpenROADMv5_example_network.json', ]), | ||||
| )) | ||||
| def test_example_invocation(capfdbinary, output, handler, args): | ||||
| def test_example_invocation(capfd, output, handler, args): | ||||
|     '''Make sure that our examples produce useful output''' | ||||
|     os.chdir(SRC_ROOT) | ||||
|     expected = open(SRC_ROOT / 'tests' / 'invocation' / output, mode='rb').read() | ||||
|     expected = open(SRC_ROOT / 'tests' / 'invocation' / output, mode='r', encoding='utf-8').read() | ||||
|     handler(args) | ||||
|     captured = capfdbinary.readouterr() | ||||
|     captured = capfd.readouterr() | ||||
|     assert captured.out == expected | ||||
|     assert captured.err == b'' | ||||
|     assert captured.err == '' | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize('program', ('gnpy-transmission-example', 'gnpy-path-request')) | ||||
| @@ -39,7 +43,7 @@ def test_run_wrapper(program): | ||||
|  | ||||
| def test_conversion_xls(): | ||||
|     proc = subprocess.run( | ||||
|         ('gnpy-convert-xls', SRC_ROOT / 'tests' / 'data' / 'testTopology.xls', '--output', '/dev/null'), | ||||
|         ('gnpy-convert-xls', SRC_ROOT / 'tests' / 'data' / 'testTopology.xls', '--output', os.path.devnull), | ||||
|         stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, universal_newlines=True) | ||||
|     assert proc.stderr == '' | ||||
|     assert '/dev/null' in proc.stdout | ||||
|     assert os.path.devnull in proc.stdout | ||||
|   | ||||
| @@ -243,35 +243,6 @@ def test_csv_response_generation(tmpdir, json_input): | ||||
|         print(type(list(resp[column])[-1])) | ||||
|  | ||||
|  | ||||
| def compare_response(exp_resp, act_resp): | ||||
|     """ False if the keys are different in the nested dicts as well | ||||
|     """ | ||||
|     print(exp_resp) | ||||
|     print(act_resp) | ||||
|     test = True | ||||
|     for key in act_resp.keys(): | ||||
|         if key not in exp_resp.keys(): | ||||
|             print(f'{key} is not expected') | ||||
|             return False | ||||
|         if isinstance(act_resp[key], dict): | ||||
|             test = compare_response(exp_resp[key], act_resp[key]) | ||||
|     if test: | ||||
|         for key in exp_resp.keys(): | ||||
|             if key not in act_resp.keys(): | ||||
|                 print(f'{key} is expected') | ||||
|                 return False | ||||
|             if isinstance(exp_resp[key], dict): | ||||
|                 test = compare_response(exp_resp[key], act_resp[key]) | ||||
|  | ||||
|     # at this point exp_resp and act_resp have the same keys. Check if their values are the same | ||||
|     for key in act_resp.keys(): | ||||
|         if not isinstance(act_resp[key], dict): | ||||
|             if exp_resp[key] != act_resp[key]: | ||||
|                 print(f'expected value :{exp_resp[key]}\n actual value: {act_resp[key]}') | ||||
|                 return False | ||||
|     return test | ||||
|  | ||||
|  | ||||
| # test json answers creation | ||||
| @pytest.mark.parametrize('xls_input, expected_response_file', { | ||||
|     DATA_DIR / 'testTopology.xls': DATA_DIR / 'testTopology_response.json', | ||||
| @@ -304,11 +275,12 @@ def test_json_response_generation(xls_input, expected_response_file): | ||||
|  | ||||
|     result = [] | ||||
|     for i, pth in enumerate(propagatedpths): | ||||
|         # test ServiceError handling : when M is zero at this point, the | ||||
|         # test ServiceError handling : when M is None at this point, the | ||||
|         # json result should not be created if there is no blocking reason | ||||
|         if i == 1: | ||||
|             my_rq = deepcopy(rqs[i]) | ||||
|             my_rq.M = 0 | ||||
|             my_rq.M = None | ||||
|             my_rq.N = None | ||||
|             with pytest.raises(ServiceError): | ||||
|                 ResultElement(my_rq, pth, reversed_propagatedpths[i]).json | ||||
|  | ||||
| @@ -327,7 +299,7 @@ def test_json_response_generation(xls_input, expected_response_file): | ||||
|         if i == 2: | ||||
|             # compare response must be False because z-a metric is missing | ||||
|             # (request with bidir option to cover bidir case) | ||||
|             assert not compare_response(expected['response'][i], response) | ||||
|             assert expected['response'][i] != response | ||||
|             print(f'response {response["response-id"]} should not match') | ||||
|             expected['response'][2]['path-properties']['z-a-path-metric'] = [ | ||||
|                 {'metric-type': 'SNR-bandwidth', 'accumulative-value': 22.809999999999999}, | ||||
| @@ -338,8 +310,7 @@ def test_json_response_generation(xls_input, expected_response_file): | ||||
|                 {'metric-type': 'path_bandwidth', 'accumulative-value': 60000000000.0}] | ||||
|             # test should be OK now | ||||
|         else: | ||||
|             assert compare_response(expected['response'][i], response) | ||||
|             print(f'response {response["response-id"]} is not correct') | ||||
|             assert expected['response'][i] == response | ||||
|  | ||||
| # test the correspondance names dict in case of excel input | ||||
| # test that using the created json network still works with excel input | ||||
| @@ -424,6 +395,7 @@ def test_excel_ila_constraints(source, destination, route_list, hoptype, expecte | ||||
|         'nb_channel': 0, | ||||
|         'power': 0, | ||||
|         'path_bandwidth': 0, | ||||
|         'effective_freq_slot': None | ||||
|     } | ||||
|     request = PathRequest(**params) | ||||
|  | ||||
|   | ||||
| @@ -207,8 +207,9 @@ def test_restrictions(restrictions, equipment): | ||||
|                     raise AssertionError() | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize('power_dbm', [0, +1, -2]) | ||||
| @pytest.mark.parametrize('prev_node_type, effective_pch_out_db', [('edfa', -20.0), ('fused', -22.0)]) | ||||
| def test_roadm_target_power(prev_node_type, effective_pch_out_db): | ||||
| def test_roadm_target_power(prev_node_type, effective_pch_out_db, power_dbm): | ||||
|     ''' Check that egress power of roadm is equal to target power if input power is greater | ||||
|     than target power else, that it is equal to input power. Use a simple two hops A-B-C topology | ||||
|     for the test where the prev_node in ROADM B is either an amplifier or a fused, so that the target | ||||
| @@ -225,28 +226,28 @@ def test_roadm_target_power(prev_node_type, effective_pch_out_db): | ||||
|         prev_node['params'] = {'loss': 0} | ||||
|     json_network['elements'].append(prev_node) | ||||
|     network = network_from_json(json_network, equipment) | ||||
|     # Build the network once using the default power defined in SI in eqpt config | ||||
|     p_db = equipment['SI']['default'].power_dbm | ||||
|     p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min, | ||||
|                                              equipment['SI']['default'].f_max,  | ||||
|                                              equipment['SI']['default'].spacing)) | ||||
|     p_total_db = power_dbm + lin2db(automatic_nch(equipment['SI']['default'].f_min, | ||||
|                                                   equipment['SI']['default'].f_max, | ||||
|                                                   equipment['SI']['default'].spacing)) | ||||
|  | ||||
|     build_network(network, equipment, p_db, p_total_db) | ||||
|     build_network(network, equipment, power_dbm, p_total_db) | ||||
|  | ||||
|     params = {} | ||||
|     params['request_id'] = 0 | ||||
|     params['trx_type'] = '' | ||||
|     params['trx_mode'] = '' | ||||
|     params['source'] = 'trx node A' | ||||
|     params['destination'] = 'trx node C' | ||||
|     params['bidir'] = False | ||||
|     params['nodes_list'] = ['trx node C'] | ||||
|     params['loose_list'] = ['strict'] | ||||
|     params['format'] = '' | ||||
|     params['path_bandwidth'] = 100e9 | ||||
|     params = {'request_id': 0, | ||||
|               'trx_type': '', | ||||
|               'trx_mode': '', | ||||
|               'source': 'trx node A', | ||||
|               'destination': 'trx node C', | ||||
|               'bidir': False, | ||||
|               'nodes_list': ['trx node C'], | ||||
|               'loose_list': ['strict'], | ||||
|               'format': '', | ||||
|               'path_bandwidth': 100e9, | ||||
|               'effective_freq_slot': None, | ||||
|               } | ||||
|     trx_params = trx_mode_params(equipment) | ||||
|     params.update(trx_params) | ||||
|     req = PathRequest(**params) | ||||
|     req.power = db2lin(power_dbm - 30) | ||||
|     path = compute_constrained_path(network, req) | ||||
|     si = create_input_spectral_information( | ||||
|         req.f_min, req.f_max, req.roll_off, req.baud_rate, | ||||
| @@ -254,10 +255,23 @@ def test_roadm_target_power(prev_node_type, effective_pch_out_db): | ||||
|     for i, el in enumerate(path): | ||||
|         if isinstance(el, Roadm): | ||||
|             carriers_power_in_roadm = min([c.power.signal + c.power.nli + c.power.ase for c in si.carriers]) | ||||
|             si = el(si, degree=path[i+1].uid) | ||||
|             si = el(si, degree=path[i + 1].uid) | ||||
|             if el.uid == 'roadm node B': | ||||
|                 print('input', carriers_power_in_roadm) | ||||
|                 assert el.effective_pch_out_db == effective_pch_out_db | ||||
|                 # if previous was an EDFA, power level at ROADM input is enough for the ROADM to apply its | ||||
|                 # target power (as specified in equipment ie -20 dBm) | ||||
|                 # if it is a Fused, the input power to the ROADM is smaller than the target power, and the | ||||
|                 # ROADM cannot apply this target. In this case, it is assumed that the ROADM has 0 dB loss | ||||
|                 # so the output power will be the same as the input power, which for this particular case | ||||
|                 # corresponds to -22dBm + power_dbm | ||||
|                 # next step (for ROADM modelling) will be to apply a minimum loss for ROADMs ! | ||||
|                 if prev_node_type == 'edfa': | ||||
|                     assert el.effective_pch_out_db == effective_pch_out_db | ||||
|                 if prev_node_type == 'fused': | ||||
|                     # then output power == input_power == effective_pch_out_db + power_dbm | ||||
|                     assert effective_pch_out_db + power_dbm == \ | ||||
|                         pytest.approx(lin2db(carriers_power_in_roadm * 1e3), rel=1e-3) | ||||
|                     assert el.effective_pch_out_db == effective_pch_out_db + power_dbm | ||||
|                 for carrier in si.carriers: | ||||
|                     print(carrier.power.signal + carrier.power.nli + carrier.power.ase) | ||||
|                     power = carrier.power.signal + carrier.power.nli + carrier.power.ase | ||||
| @@ -272,4 +286,3 @@ def test_roadm_target_power(prev_node_type, effective_pch_out_db): | ||||
|                         assert power == pytest.approx(carriers_power_in_roadm, rel=1e-3) | ||||
|         else: | ||||
|             si = el(si) | ||||
|  | ||||
|   | ||||
| @@ -17,11 +17,12 @@ import pytest | ||||
| from gnpy.core.network import build_network | ||||
| from gnpy.core.utils import lin2db, automatic_nch | ||||
| from gnpy.core.elements import Roadm, Transceiver | ||||
| from gnpy.core.exceptions import SpectrumError | ||||
| from gnpy.topology.request import compute_path_dsjctn, find_reversed_path, deduplicate_disjunctions | ||||
| from gnpy.core.exceptions import ServiceError, SpectrumError | ||||
| from gnpy.topology.request import compute_path_dsjctn, find_reversed_path, deduplicate_disjunctions, PathRequest | ||||
| from gnpy.topology.spectrum_assignment import (build_oms_list, align_grids, nvalue_to_frequency, | ||||
|                                            bitmap_sum, Bitmap, spectrum_selection, pth_assign_spectrum) | ||||
| from gnpy.tools.json_io import load_equipment, load_network, requests_from_json, disjunctions_from_json | ||||
| from gnpy.tools.json_io import (load_equipment, load_network, requests_from_json, disjunctions_from_json, | ||||
|                                 _check_one_request) | ||||
|  | ||||
| TEST_DIR = Path(__file__).parent | ||||
| DATA_DIR = TEST_DIR / 'data' | ||||
| @@ -267,6 +268,108 @@ def test_spectrum_assignment_on_path(equipment, setup, requests): | ||||
|     assert center_n is not None and startn is not None and stopn is not None | ||||
|  | ||||
|  | ||||
| @pytest.fixture() | ||||
| def request_set(): | ||||
|     """ creates default request dict | ||||
|     """ | ||||
|     return { | ||||
|         'request_id': '0', | ||||
|         'source': 'trx a', | ||||
|         'bidir': False, | ||||
|         'destination': 'trx g', | ||||
|         'trx_type': 'Voyager', | ||||
|         'trx_mode': 'mode 1', | ||||
|         'format': 'mode1', | ||||
|         'spacing': 50e9, | ||||
|         'nodes_list': [], | ||||
|         'loose_list': [], | ||||
|         'f_min': 191.1e12, | ||||
|         'f_max': 196.3e12, | ||||
|         'baud_rate': 32e9, | ||||
|         'OSNR': 14, | ||||
|         'bit_rate': 100e9, | ||||
|         'cost': 1, | ||||
|         'roll_off': 0.15, | ||||
|         'tx_osnr': 38, | ||||
|         'min_spacing': 37.5e9, | ||||
|         'nb_channel': None, | ||||
|         'power': 0, | ||||
|         'path_bandwidth': 800e9} | ||||
|  | ||||
|  | ||||
| def test_freq_slot_exist(setup, equipment, request_set): | ||||
|     """ test that assignment works even if effective_freq_slot is not populated | ||||
|     """ | ||||
|     network, oms_list = setup | ||||
|     params = request_set | ||||
|     params['effective_freq_slot'] = None | ||||
|     rqs = [PathRequest(**params)] | ||||
|     paths = compute_path_dsjctn(network, equipment, rqs, []) | ||||
|     pth_assign_spectrum(paths, rqs, oms_list, [find_reversed_path(paths[0])]) | ||||
|     assert rqs[0].N == -256 | ||||
|     assert rqs[0].M == 32 | ||||
|  | ||||
|  | ||||
| def test_inconsistant_freq_slot(setup, equipment, request_set): | ||||
|     """ test that an inconsistant M correctly raises an error | ||||
|     """ | ||||
|     network, oms_list = setup | ||||
|     params = request_set | ||||
|     # minimum required nb of slots is 32 (800Gbit/100Gbit/s channels each occupying 50GHz ie 4 slots) | ||||
|     params['effective_freq_slot'] = {'N': 0, 'M': 4} | ||||
|     with pytest.raises(ServiceError): | ||||
|         _check_one_request(params, 196.05e12) | ||||
|     params['trx_mode'] = None | ||||
|     rqs = [PathRequest(**params)] | ||||
|     paths = compute_path_dsjctn(network, equipment, rqs, []) | ||||
|     pth_assign_spectrum(paths, rqs, oms_list, [find_reversed_path(paths[0])]) | ||||
|     assert rqs[0].blocking_reason == 'NOT_ENOUGH_RESERVED_SPECTRUM' | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize('n, m, final_n, final_m, blocking_reason', [ | ||||
|     # regular requests that should be correctly assigned: | ||||
|     (-100, 32, -100, 32, None), | ||||
|     (150, 50, 150, 50, None), | ||||
|     # if n is None, there should be an assignment (enough spectrum cases) | ||||
|     # and the center frequency should be set on the lower part of the spectrum based on m value if it exists | ||||
|     # or based on 32 | ||||
|     (None, 32, -256, 32, None), | ||||
|     (None, 40, -248, 40, None), | ||||
|     (-100, None, -100, 32, None), | ||||
|     (None, None, -256, 32, None), | ||||
|     # -280 and 60 center indexes should result in unfeasible spectrum, either out of band or | ||||
|     # overlapping with occupied spectrum. The requested spectrum is not available | ||||
|     (-280, None, None, None, 'NO_SPECTRUM'), | ||||
|     (-60, 40, None, None, 'NO_SPECTRUM'), | ||||
|     # 20 is smaller than min 32 required nb of slots so should also be blocked | ||||
|     (-60, 20, None, None, 'NOT_ENOUGH_RESERVED_SPECTRUM') | ||||
|     ]) | ||||
| def test_n_m_requests(setup, equipment, n, m, final_n, final_m, blocking_reason, request_set): | ||||
|     """ test that various N and M values for a request end up with the correct path assgnment | ||||
|     """ | ||||
|     network, oms_list = setup | ||||
|     # add an occupation on one of the span of the expected path OMS list on both directions | ||||
|     # as defined by its offsets within the OMS list: [17, 20, 13, 22] and reversed path [19, 16, 21, 26] | ||||
|     expected_path = [17, 20, 13, 22] | ||||
|     expected_oms = [13, 16, 17, 19, 20, 21, 22, 26] | ||||
|     some_oms = oms_list[expected_oms[3]] | ||||
|     some_oms.assign_spectrum(-30, 32)    # means that spectrum is occupied from indexes -62 to 1 on reversed path | ||||
|     params = request_set | ||||
|     params['effective_freq_slot'] = {'N': n, 'M': m} | ||||
|     rqs = [PathRequest(**params)] | ||||
|  | ||||
|     paths = compute_path_dsjctn(network, equipment, rqs, []) | ||||
|     # check that the computed path is the expected one (independant of blocking issues due to spectrum) | ||||
|     path_oms = list(set([e.oms_id for e in paths[0] if not isinstance(e, (Transceiver, Roadm))])) | ||||
|     assert path_oms == expected_path | ||||
|     # function to be tested: | ||||
|     pth_assign_spectrum(paths, rqs, oms_list, [find_reversed_path(paths[0])]) | ||||
|     # check that spectrum is correctly assigned | ||||
|     assert rqs[0].N == final_n | ||||
|     assert rqs[0].M == final_m | ||||
|     assert getattr(rqs[0], 'blocking_reason', None) == blocking_reason | ||||
|  | ||||
|  | ||||
| def test_reversed_direction(equipment, setup, requests, services): | ||||
|     """ checks that if spectrum is selected on one direction it is also selected on reversed | ||||
|         direction | ||||
|   | ||||
		Reference in New Issue
	
	Block a user