mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-29 17:22:42 +00:00
fix: PMD was not correctly read from excel or exported from json
Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com> Change-Id: I1069b07dfb62bf94d4f591908c034df4e49ce22a
This commit is contained in:
@@ -891,18 +891,23 @@ class Fiber(_Node):
|
||||
|
||||
:return Dict[str, Any]: JSON representation of the fiber.
|
||||
"""
|
||||
params = {
|
||||
# have to specify each because namedtupple cannot be updated :(
|
||||
'length': round(self.params.length * 1e-3, 6),
|
||||
'loss_coef': round(self.params.loss_coef * 1e3, 6),
|
||||
'length_units': 'km',
|
||||
'att_in': self.params.att_in,
|
||||
'con_in': self.params.con_in,
|
||||
'con_out': self.params.con_out
|
||||
}
|
||||
# Export pmd_coef only if it is not a default from library.
|
||||
if self.params.pmd_coef_defined:
|
||||
params['pmd_coef'] = self.params.pmd_coef
|
||||
|
||||
return {'uid': self.uid,
|
||||
'type': type(self).__name__,
|
||||
'type_variety': self.type_variety,
|
||||
'params': {
|
||||
# have to specify each because namedtupple cannot be updated :(
|
||||
'length': round(self.params.length * 1e-3, 6),
|
||||
'loss_coef': round(self.params.loss_coef * 1e3, 6),
|
||||
'length_units': 'km',
|
||||
'att_in': self.params.att_in,
|
||||
'con_in': self.params.con_in,
|
||||
'con_out': self.params.con_out
|
||||
},
|
||||
'params': params,
|
||||
'metadata': {
|
||||
'location': self.metadata['location']._asdict()
|
||||
}
|
||||
@@ -1025,7 +1030,7 @@ class Fiber(_Node):
|
||||
else:
|
||||
wavelength = c / frequency
|
||||
dispersion = self.params.dispersion + self.params.dispersion_slope * \
|
||||
(wavelength - c / self.params.f_dispersion_ref)
|
||||
(wavelength - c / self.params.f_dispersion_ref) # noqa E127
|
||||
beta2 = -((c / frequency) ** 2 * dispersion) / (2 * pi * c)
|
||||
return beta2
|
||||
|
||||
@@ -1048,7 +1053,7 @@ class Fiber(_Node):
|
||||
dispersion_slope = self.params.dispersion_slope
|
||||
beta2 = self.beta2(frequency)
|
||||
beta3 = (dispersion_slope - (4 * pi * frequency ** 3 / c ** 2) * beta2) / (
|
||||
2 * pi * frequency ** 2 / c) ** 2
|
||||
2 * pi * frequency ** 2 / c) ** 2 # noqa E127
|
||||
return beta3
|
||||
|
||||
def gamma(self, frequency=None):
|
||||
|
||||
@@ -343,6 +343,7 @@ class FiberParams(Parameters):
|
||||
|
||||
# Polarization Mode Dispersion
|
||||
self._pmd_coef = kwargs['pmd_coef'] # s/sqrt(m)
|
||||
self._pmd_coef_defined = kwargs.get('pmd_coef_defined', kwargs['pmd_coef'] is True)
|
||||
|
||||
# Loss Coefficient
|
||||
if isinstance(kwargs['loss_coef'], dict):
|
||||
@@ -428,6 +429,10 @@ class FiberParams(Parameters):
|
||||
def pmd_coef(self):
|
||||
return self._pmd_coef
|
||||
|
||||
@property
|
||||
def pmd_coef_defined(self):
|
||||
return self._pmd_coef_defined
|
||||
|
||||
@property
|
||||
def ref_wavelength(self):
|
||||
return self._ref_wavelength
|
||||
|
||||
@@ -329,6 +329,35 @@ def merge_amplifier_restrictions(dict1, dict2):
|
||||
return copy_dict1
|
||||
|
||||
|
||||
def use_pmd_coef(dict1: dict, dict2: dict):
|
||||
"""If Fiber dict1 is missing the pmd_coef value then use the one of dict2.
|
||||
In addition records in "pmd_coef_defined" key the pmd_coef if is was defined in dict1.
|
||||
|
||||
:param dict1: A dictionnary that contains "pmd_coef" key.
|
||||
:type dict1: dict
|
||||
:param dict2: Another dictionnary that contains "pmd_coef" key.
|
||||
:type dict2: dict
|
||||
|
||||
>>> dict1 = {'a': 1, 'pmd_coef': 1.5e-15}
|
||||
>>> dict2 = {'a': 2, 'pmd_coef': 2e-15}
|
||||
>>> use_pmd_coef(dict1, dict2)
|
||||
>>> dict1
|
||||
{'a': 1, 'pmd_coef': 1.5e-15, 'pmd_coef_defined': True}
|
||||
|
||||
>>> dict1 = {'a': 1}
|
||||
>>> use_pmd_coef(dict1, dict2)
|
||||
>>> dict1
|
||||
{'a': 1, 'pmd_coef_defined': False, 'pmd_coef': 2e-15}
|
||||
"""
|
||||
if 'pmd_coef' in dict1 and not dict1['pmd_coef'] \
|
||||
or ('pmd_coef' not in dict1 and 'pmd_coef' in dict2):
|
||||
dict1['pmd_coef_defined'] = False
|
||||
dict1['pmd_coef'] = dict2['pmd_coef']
|
||||
elif 'pmd_coef' in dict1 and dict1['pmd_coef']:
|
||||
dict1['pmd_coef_defined'] = True
|
||||
# all other case do not need any change
|
||||
|
||||
|
||||
def silent_remove(this_list, elem):
|
||||
"""Remove matching elements from a list without raising ValueError
|
||||
|
||||
@@ -558,3 +587,23 @@ def transform_data(data: str) -> Union[List[int], None]:
|
||||
if isinstance(data, str):
|
||||
return [int(x) for x in data.split(' | ')]
|
||||
return None
|
||||
|
||||
|
||||
def convert_pmd_lineic(pmd: Union[float, None], length: float, length_unit: str) -> Union[float, None]:
|
||||
"""Convert PMD value of the span in ps into pmd_lineic in s/sqrt(km)
|
||||
|
||||
:param pmd: value in ps
|
||||
:type pmd: Union[float, None]
|
||||
:param length: value in length_unit
|
||||
:type length: float
|
||||
:param length_unit: 'km' or 'm'
|
||||
:type length_unit: str
|
||||
:return: lineic PMD s/sqrt(m)
|
||||
:rtype: Union[float, None]
|
||||
|
||||
>>> convert_pmd_lineic(10, 0.001, 'km')
|
||||
1e-11
|
||||
"""
|
||||
if pmd:
|
||||
return pmd * 1e-12 / sqrt(convert_length(length, length_unit))
|
||||
return None
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
"con_out": 0.5,
|
||||
"pmd_coef": 3.0e-15
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
|
||||
Binary file not shown.
@@ -33,7 +33,7 @@ from xlrd.sheet import Sheet
|
||||
from xlrd.biffh import XLRDError
|
||||
from networkx import DiGraph
|
||||
|
||||
from gnpy.core.utils import silent_remove, transform_data
|
||||
from gnpy.core.utils import silent_remove, transform_data, convert_pmd_lineic
|
||||
from gnpy.core.exceptions import NetworkTopologyError
|
||||
from gnpy.core.elements import Edfa, Fused, Fiber
|
||||
|
||||
@@ -170,7 +170,7 @@ class Link:
|
||||
'east_lineic': 0.2,
|
||||
'east_con_in': None,
|
||||
'east_con_out': None,
|
||||
'east_pmd': 0.1,
|
||||
'east_pmd': None,
|
||||
'east_cable': ''
|
||||
}
|
||||
|
||||
@@ -636,6 +636,62 @@ def create_west_eqpt_element(node: Node, nodes_by_city: Dict[str, Node]) -> dict
|
||||
return eqpt
|
||||
|
||||
|
||||
def create_east_fiber_element(fiber: Node, nodes_by_city: Dict[str, Node]) -> Dict:
|
||||
"""Create fibers json elements for the east direction.
|
||||
|
||||
:param fiber: The Node object representing the equipment.
|
||||
:type fiber: Node
|
||||
:param nodes_by_city: A dictionary mapping city names to Node objects.
|
||||
:type nodes_by_city: Dict[str, Node]
|
||||
:return: A dictionary representing the west equipment element in JSON format.
|
||||
:rtype: Dict
|
||||
"""
|
||||
fiber_dict = {
|
||||
'uid': f'fiber ({fiber.from_city} \u2192 {fiber.to_city})-{fiber.east_cable}',
|
||||
'metadata': {'location': midpoint(nodes_by_city[fiber.from_city],
|
||||
nodes_by_city[fiber.to_city])},
|
||||
'type': 'Fiber',
|
||||
'type_variety': fiber.east_fiber,
|
||||
'params': {
|
||||
'length': round(fiber.east_distance, 3),
|
||||
'length_units': fiber.distance_units,
|
||||
'loss_coef': fiber.east_lineic,
|
||||
'con_in': fiber.east_con_in,
|
||||
'con_out': fiber.east_con_out
|
||||
}
|
||||
}
|
||||
if fiber.east_pmd:
|
||||
fiber_dict['params']['pmd_coef'] = convert_pmd_lineic(fiber.east_pmd, fiber.east_distance, fiber.distance_units)
|
||||
return fiber_dict
|
||||
|
||||
|
||||
def create_west_fiber_element(fiber: Node, nodes_by_city: Dict[str, Node]) -> Dict:
|
||||
"""Create fibers json elements for the west direction.
|
||||
|
||||
:param fiber: The Node object representing the equipment.
|
||||
:type fiber: Node
|
||||
:param nodes_by_city: A dictionary mapping city names to Node objects.
|
||||
:type nodes_by_city: Dict[str, Node]
|
||||
:return: A dictionary representing the west equipment element in JSON format.
|
||||
:rtype: Dict
|
||||
"""
|
||||
fiber_dict = {
|
||||
'uid': f'fiber ({fiber.to_city} \u2192 {fiber.from_city})-{fiber.west_cable}',
|
||||
'metadata': {'location': midpoint(nodes_by_city[fiber.from_city],
|
||||
nodes_by_city[fiber.to_city])},
|
||||
'type': 'Fiber',
|
||||
'type_variety': fiber.west_fiber,
|
||||
'params': {'length': round(fiber.west_distance, 3),
|
||||
'length_units': fiber.distance_units,
|
||||
'loss_coef': fiber.west_lineic,
|
||||
'con_in': fiber.west_con_in,
|
||||
'con_out': fiber.west_con_out}
|
||||
}
|
||||
if fiber.west_pmd:
|
||||
fiber_dict['params']['pmd_coef'] = convert_pmd_lineic(fiber.west_pmd, fiber.west_distance, fiber.distance_units)
|
||||
return fiber_dict
|
||||
|
||||
|
||||
def xls_to_json_data(input_filename: Path, filter_region: List[str] = None) -> dict:
|
||||
"""Read the Excel sheets and produce the JSON dict in GNPy format (legacy).
|
||||
|
||||
@@ -698,29 +754,8 @@ def xls_to_json_data(input_filename: Path, filter_region: List[str] = None) -> d
|
||||
'longitude': x.longitude}},
|
||||
'type': 'Fused'}
|
||||
for x in nodes_by_city.values() if x.node_type.lower() == 'fused']
|
||||
+ [{'uid': f'fiber ({x.from_city} \u2192 {x.to_city})-{x.east_cable}',
|
||||
'metadata': {'location': midpoint(nodes_by_city[x.from_city],
|
||||
nodes_by_city[x.to_city])},
|
||||
'type': 'Fiber',
|
||||
'type_variety': x.east_fiber,
|
||||
'params': {'length': round(x.east_distance, 3),
|
||||
'length_units': x.distance_units,
|
||||
'loss_coef': x.east_lineic,
|
||||
'con_in': x.east_con_in,
|
||||
'con_out': x.east_con_out}
|
||||
}
|
||||
for x in links]
|
||||
+ [{'uid': f'fiber ({x.to_city} \u2192 {x.from_city})-{x.west_cable}',
|
||||
'metadata': {'location': midpoint(nodes_by_city[x.from_city],
|
||||
nodes_by_city[x.to_city])},
|
||||
'type': 'Fiber',
|
||||
'type_variety': x.west_fiber,
|
||||
'params': {'length': round(x.west_distance, 3),
|
||||
'length_units': x.distance_units,
|
||||
'loss_coef': x.west_lineic,
|
||||
'con_in': x.west_con_in,
|
||||
'con_out': x.west_con_out}
|
||||
} for x in links]
|
||||
+ [create_east_fiber_element(x, nodes_by_city) for x in links]
|
||||
+ [create_west_fiber_element(x, nodes_by_city) for x in links]
|
||||
+ [{'uid': f'west edfa in {x.city}',
|
||||
'metadata': {'location': {'city': x.city,
|
||||
'region': x.region,
|
||||
|
||||
@@ -23,7 +23,7 @@ from gnpy.core.equipment import trx_mode_params, find_type_variety
|
||||
from gnpy.core.exceptions import ConfigurationError, EquipmentConfigError, NetworkTopologyError, ServiceError
|
||||
from gnpy.core.science_utils import estimate_nf_model
|
||||
from gnpy.core.info import Carrier
|
||||
from gnpy.core.utils import automatic_nch, automatic_fmax, merge_amplifier_restrictions, dbm2watt
|
||||
from gnpy.core.utils import automatic_nch, automatic_fmax, merge_amplifier_restrictions, dbm2watt, use_pmd_coef
|
||||
from gnpy.core.parameters import DEFAULT_RAMAN_COEFFICIENT, EdfaParams, MultiBandParams, DEFAULT_EDFA_CONFIG
|
||||
from gnpy.topology.request import PathRequest, Disjunction, compute_spectrum_slot_vs_bandwidth, ResultElement
|
||||
from gnpy.topology.spectrum_assignment import mvalue_to_slots
|
||||
@@ -687,6 +687,9 @@ def network_from_json(json_data: dict, equipment: dict) -> DiGraph:
|
||||
if not extra_params:
|
||||
msg = f'ROADM {el_config["uid"]}: invalid equalization settings'
|
||||
raise ConfigurationError(msg)
|
||||
# use temp pmd_coef if it exists else use the default one from library and keep this knowledge in
|
||||
# pmd_coef_defined
|
||||
use_pmd_coef(temp, extra_params)
|
||||
temp = merge_amplifier_restrictions(temp, extra_params)
|
||||
el_config['params'] = temp
|
||||
el_config['type_variety'] = variety
|
||||
|
||||
@@ -101,7 +101,7 @@ Transceiver trx Lorient_KMA
|
||||
OSNR ASE (0.1nm, dB): 23.89
|
||||
OSNR ASE (signal bw, dB): 19.81
|
||||
CD (ps/nm): 2171.00
|
||||
PMD (ps): 0.46
|
||||
PMD (ps): 3.03
|
||||
PDL (dB): 0.00
|
||||
Latency (ms): 0.64
|
||||
Actual pch out (dBm): 0.00
|
||||
|
||||
@@ -101,7 +101,7 @@ Transceiver trx Lorient_KMA
|
||||
OSNR ASE (0.1nm, dB): mode_1: 23.91, mode_2: 23.87
|
||||
OSNR ASE (signal bw, dB): mode_1: 19.83, mode_2: 16.78
|
||||
CD (ps/nm): 2171.00
|
||||
PMD (ps): 0.46
|
||||
PMD (ps): 3.03
|
||||
PDL (dB): 0.00
|
||||
Latency (ms): 0.64
|
||||
Actual pch out (dBm): mode_1: 0.00, mode_2: 0.00
|
||||
|
||||
@@ -52,7 +52,7 @@ Transceiver Site_B
|
||||
OSNR ASE (0.1nm, dB): 33.30
|
||||
OSNR ASE (signal bw, dB): 29.21
|
||||
CD (ps/nm): 1336.00
|
||||
PMD (ps): 0.36
|
||||
PMD (ps): 0.85
|
||||
PDL (dB): 0.00
|
||||
Latency (ms): 0.39
|
||||
Actual pch out (dBm): 0.00
|
||||
|
||||
@@ -377,8 +377,8 @@ def wrong_element():
|
||||
"expected_msg": "Config error in fiber (ILA2 → ILA1): "
|
||||
+ "Fiber configurations json must include \'length_units\'. Configuration: "
|
||||
+ "{\'length\': 100.0, \'loss_coef\': 0.2, \'att_in\': 0, \'con_in\': 0, \'con_out\': 0, "
|
||||
+ "\'type_variety\': \'SSMF\', \'dispersion\': 1.67e-05, \'effective_area\': 8.3e-11, "
|
||||
+ "\'pmd_coef\': 1.265e-15}"
|
||||
+ "\'pmd_coef_defined': False, \'pmd_coef\': 1.265e-15, "
|
||||
+ "\'type_variety\': \'SSMF\', \'dispersion\': 1.67e-05, \'effective_area\': 8.3e-11}"
|
||||
})
|
||||
return data
|
||||
|
||||
|
||||
Reference in New Issue
Block a user