2 * Copyright © 2022 Orange, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.transportpce.common.catalog;
10 import java.util.HashMap;
12 import java.util.Optional;
13 import java.util.concurrent.ExecutionException;
14 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
15 import org.opendaylight.transportpce.common.StringConstants;
16 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
17 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.link.types.rev191129.RatioDB;
18 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.ImpairmentType;
19 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.amplifier.parameters.Amplifier;
20 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.OpenroadmOperationalModes;
21 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.SpecificOperationalModes;
22 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.openroadm.operational.modes.Amplifiers;
23 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.openroadm.operational.modes.Roadms;
24 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.openroadm.operational.modes.XpondersPluggables;
25 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.openroadm.operational.modes.xponders.pluggables.XponderPluggableOpenroadmOperationalMode;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.openroadm.operational.modes.xponders.pluggables.XponderPluggableOpenroadmOperationalModeKey;
27 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.specific.operational.modes.SpecificOperationalMode;
28 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.specific.operational.modes.SpecificOperationalModeKey;
29 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.common.amplifier.drop.parameters.OpenroadmOperationalMode;
30 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.common.amplifier.drop.parameters.OpenroadmOperationalModeKey;
31 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.roadm.add.parameters.Add;
32 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.roadm.add.parameters.add.AddOpenroadmOperationalMode;
33 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.roadm.add.parameters.add.AddOpenroadmOperationalModeKey;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.roadm.drop.parameters.Drop;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.roadm.express.parameters.Express;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.transponder.parameters.Penalties;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.transponder.parameters.PenaltiesKey;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.transponder.parameters.TXOOBOsnrKey;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.OperationalModeCatalog;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * Utility class for Catalog. Following methods are used to retrieve parameters
46 * from the specification catalog. They point to either openROADM or specific
47 * operational modes. They provide to the PCE, the OLM and the Renderer, the
48 * required parameters to calculate impairments and set output power levels
49 * according to the specifications.
52 public class CatalogUtils {
54 private static final Logger LOG = LoggerFactory.getLogger(CatalogUtils.class);
56 private static final String OPMODE_MISMATCH_MSG =
57 "Operational Mode {} passed to getPceRoadmAmpParameters does not correspond to an OpenROADM mode"
58 + "Parameters for amplifier and/or ROADMs can not be derived from specific-operational-modes.";
59 private static final Map<CatalogConstant.CatalogNodeType, String> CATALOGNODETYPE_OPERATIONMODEID_MAP = Map.of(
60 CatalogConstant.CatalogNodeType.ADD, CatalogConstant.MWWRCORE,
61 CatalogConstant.CatalogNodeType.DROP, CatalogConstant.MWWRCORE,
62 CatalogConstant.CatalogNodeType.EXPRESS, CatalogConstant.MWMWCORE,
63 CatalogConstant.CatalogNodeType.AMP, CatalogConstant.MWISTANDARD);
64 private static final Map<String, String> TSP_DEFAULT_OM_MAP = Map.of(
65 StringConstants.SERVICE_TYPE_100GE_T, CatalogConstant.ORW100GSC,
66 StringConstants.SERVICE_TYPE_OTU4, CatalogConstant.ORW100GSC,
67 StringConstants.SERVICE_TYPE_OTUC2, CatalogConstant.ORW200GOFEC316GBD,
68 StringConstants.SERVICE_TYPE_OTUC3, CatalogConstant.ORW300GOFEC631GBD,
69 StringConstants.SERVICE_TYPE_OTUC4, CatalogConstant.ORW400GOFEC631GBD,
70 StringConstants.SERVICE_TYPE_400GE, CatalogConstant.ORW400GOFEC631GBD);
72 private final PenaltiesComparator penaltiesComparator = new PenaltiesComparator();
73 private NetworkTransactionService networkTransactionService;
75 public CatalogUtils(NetworkTransactionService networkTransactionService) {
76 this.networkTransactionService = networkTransactionService;
80 * Following method returns default OperationalModeId for devices that do not expose them.
82 * @param catalogNodeType
83 * identifies type of nodes in the catalog
85 * allows for Xponder selecting default mode according to the rate
87 * @return a default operational mode that corresponds to initial specifications
90 public String getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType catalogNodeType,
92 if (CATALOGNODETYPE_OPERATIONMODEID_MAP.containsKey(catalogNodeType)) {
93 return CATALOGNODETYPE_OPERATIONMODEID_MAP.get(catalogNodeType);
95 if (!catalogNodeType.equals(CatalogConstant.CatalogNodeType.TSP)) {
96 LOG.warn("Unsupported catalogNodeType {}", catalogNodeType);
99 if (!TSP_DEFAULT_OM_MAP.containsKey(serviceType)) {
100 LOG.warn("Unsupported serviceType {} for TSP catalogNodeType", serviceType);
103 return TSP_DEFAULT_OM_MAP.get(serviceType);
107 * This method retrieves channel-spacing associated with a Xponder TX.
109 * @param operationalModeId
110 * operational-mode-Id of the Xponder (OR or Specific)
112 * @return the channel spacing used to correct OSNR contribution values from
113 * ROADMs and amplifiers
114 * @throws RuntimeException
115 * if operationalModeId is not described in the catalog
118 public double getPceTxTspChannelSpacing(String operationalModeId) {
121 if (operationalModeId.startsWith("OR")) {
122 InstanceIdentifier<XponderPluggableOpenroadmOperationalMode> omCatalogIid = InstanceIdentifier
123 .builder(OperationalModeCatalog.class)
124 .child(OpenroadmOperationalModes.class)
125 .child(XpondersPluggables.class)
126 .child(XponderPluggableOpenroadmOperationalMode.class,
127 new XponderPluggableOpenroadmOperationalModeKey(operationalModeId))
130 Optional<XponderPluggableOpenroadmOperationalMode> omOptional =
131 networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
132 if (omOptional.isEmpty()) {
133 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , empty list", omCatalogIid);
136 XponderPluggableOpenroadmOperationalMode orTspOM = omOptional.get();
137 maxRollOff = orTspOM.getMaxRollOff() == null ? 0 : orTspOM.getMaxRollOff().doubleValue();
138 baudRate = orTspOM.getBaudRate().doubleValue();
139 } catch (InterruptedException | ExecutionException e) {
140 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
141 throw new RuntimeException("Operational mode not populated in Catalog : " + omCatalogIid + " :" + e);
143 networkTransactionService.close();
146 // In other cases, means the mode is a non OpenROADM specific Operational Mode
147 InstanceIdentifier<SpecificOperationalMode> omCatalogIid = InstanceIdentifier
148 .builder(OperationalModeCatalog.class)
149 .child(SpecificOperationalModes.class)
150 .child(SpecificOperationalMode.class, new SpecificOperationalModeKey(operationalModeId))
154 networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
155 if (somOptional.isEmpty()) {
156 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , empty list", omCatalogIid);
159 SpecificOperationalMode speTspOM = somOptional.get();
160 maxRollOff = speTspOM.getMaxRollOff() == null ? 0 : speTspOM.getMaxRollOff().doubleValue();
161 baudRate = speTspOM.getBaudRate().doubleValue();
162 } catch (InterruptedException | ExecutionException e) {
163 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
164 throw new RuntimeException("Operational mode not populated in Catalog : " + omCatalogIid + " :" + e);
166 networkTransactionService.close();
169 if (maxRollOff == 0) {
170 if (CatalogConstant.ORW100GSC.contentEquals(operationalModeId)) {
171 // OR 100G SCFEC is the only case where rolloff factor is not mandatory in the catalog
172 LOG.info("Operational Mode {} associated channel spacing is 50.0", operationalModeId);
175 LOG.warn("Missing rolloff factor (mandatory in Catalog) from Operational Mode {}: use default=0.2",
179 double spacing = 12.5 * Math.ceil(baudRate * (1 + maxRollOff) / 12.5);
180 LOG.info("Operational Mode {} associated channel spacing is {}", operationalModeId, spacing);
185 * This method retrieves performance parameters associated with a Xponder TX.
187 * @param operationalModeId
188 * operational-mode-Id of the Xponder (OR or Specific)
189 * @param addDropMuxOperationalModeId
190 * operational-mode-Id of the Add-Drop bloc the XponderTX is
191 * associated to (conditions TX-OOB OSNR value)
193 * @return the linear Optical Noise to signal Ratio
194 * @throws RuntimeException
195 * if operationalModeId is not described in the catalog
197 public double getPceTxTspParameters(String operationalModeId, String addDropMuxOperationalModeId) {
198 double txOnsrLin = 0.0;
199 XponderPluggableOpenroadmOperationalMode orTspOM = null;
200 SpecificOperationalMode speTspOM = null;
201 RatioDB minOOBOsnrSingleChannelValue;
202 RatioDB minOOBOsnrMultiChannelValue;
203 if (operationalModeId.startsWith("OR")) {
204 InstanceIdentifier<XponderPluggableOpenroadmOperationalMode> omCatalogIid = InstanceIdentifier
205 .builder(OperationalModeCatalog.class)
206 .child(OpenroadmOperationalModes.class)
207 .child(XpondersPluggables.class)
208 .child(XponderPluggableOpenroadmOperationalMode.class,
209 new XponderPluggableOpenroadmOperationalModeKey(operationalModeId))
212 Optional<XponderPluggableOpenroadmOperationalMode> omOptional =
213 networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
214 if (omOptional.isEmpty()) {
215 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , empty list", omCatalogIid);
218 orTspOM = omOptional.get();
219 LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orTspOM);
220 TXOOBOsnrKey key = new TXOOBOsnrKey(addDropMuxOperationalModeId);
221 if (orTspOM.getMinTXOsnr() != null) {
222 txOnsrLin = 1.0 / Math.pow(10.0, orTspOM.getMinTXOsnr().getValue().doubleValue() / 10.0);
224 if (orTspOM.nonnullTXOOBOsnr().get(key) == null) {
227 minOOBOsnrSingleChannelValue = orTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrSingleChannelValue();
228 minOOBOsnrMultiChannelValue = orTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrMultiChannelValue();
229 } catch (InterruptedException | ExecutionException e) {
230 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
231 throw new RuntimeException(
232 "readMdSal: Error reading from operational store, Operational Mode Catalog : "
233 + omCatalogIid + " :" + e);
235 networkTransactionService.close();
238 // In other cases, means the mode is a non OpenROADM specific Operational Mode
239 InstanceIdentifier<SpecificOperationalMode> omCatalogIid = InstanceIdentifier
240 .builder(OperationalModeCatalog.class)
241 .child(SpecificOperationalModes.class)
242 .child(SpecificOperationalMode.class, new SpecificOperationalModeKey(operationalModeId))
246 networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
247 if (somOptional.isEmpty()) {
248 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , empty list", omCatalogIid);
251 speTspOM = somOptional.get();
252 LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", speTspOM);
253 TXOOBOsnrKey key = new TXOOBOsnrKey(addDropMuxOperationalModeId);
254 if (speTspOM.getMinTXOsnr() != null) {
255 txOnsrLin = 1.0 / Math.pow(10.0, speTspOM.getMinTXOsnr().getValue().doubleValue() / 10.0);
257 if (speTspOM.nonnullTXOOBOsnr().get(key) == null) {
260 minOOBOsnrSingleChannelValue = speTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrSingleChannelValue();
261 minOOBOsnrMultiChannelValue = speTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrMultiChannelValue();
262 } catch (InterruptedException | ExecutionException e) {
263 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
264 throw new RuntimeException(
265 "readMdSal: Error reading from operational store, Operational Mode Catalog : " + omCatalogIid + " :"
268 networkTransactionService.close();
271 if (minOOBOsnrSingleChannelValue != null) {
272 txOnsrLin += 1.0 / Math.pow(10.0, minOOBOsnrSingleChannelValue.getValue().doubleValue() / 10.0);
274 if (minOOBOsnrMultiChannelValue != null) {
275 txOnsrLin += 1.0 / Math.pow(10.0, minOOBOsnrMultiChannelValue.getValue().doubleValue() / 10.0);
281 * This method retrieves performance parameters associated with a Xponder RX.
282 * It calls getRxTspPenalty to evaluate the penalty associated with CD/PMD/PDL
283 * It compares expected OSNR with the OSNR resulting from the line degradation,
284 * and finally calculates and return the resulting margin.
286 * @param operationalModeId
287 * operational-mode-Id of the Xponder (OR or Specific)
289 * accumulated chromatic dispersion across the line
291 * accumulated Polarization mode dispersion across the line
293 * accumulated Polarization Dependant Loss across the line
295 * Optical Signal to Noise Ratio (dB)resulting from the transmission
296 * on the line, that shall include the Non Linear contribution
298 * @return the margin on the service path
299 * @throws RuntimeException
300 * if operationalModeId is not described in the catalog
302 public double getPceRxTspParameters(String operationalModeId, double calcCd, double calcPmd,
303 double calcPdl, double calcOsnrdB) {
304 double rxOsnrdB = 0.0;
305 XponderPluggableOpenroadmOperationalMode orTspOM = null;
306 SpecificOperationalMode speTspOM = null;
307 Map<PenaltiesKey, Penalties> penaltiesMap = null;
308 if (operationalModeId.startsWith("OR")) {
309 var omCatalogIid = InstanceIdentifier
310 .builder(OperationalModeCatalog.class)
311 .child(OpenroadmOperationalModes.class)
312 .child(XpondersPluggables.class)
313 .child(XponderPluggableOpenroadmOperationalMode.class,
314 new XponderPluggableOpenroadmOperationalModeKey(operationalModeId))
317 Optional<XponderPluggableOpenroadmOperationalMode> omOptional = networkTransactionService
318 .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
319 if (omOptional.isPresent()) {
320 orTspOM = omOptional.get();
321 LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orTspOM);
322 if (orTspOM.getMinRXOsnrTolerance() != null) {
323 rxOsnrdB = orTspOM.getMinRXOsnrTolerance().getValue().doubleValue();
325 penaltiesMap = orTspOM.getPenalties();
327 } catch (InterruptedException | ExecutionException e) {
328 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
329 throw new RuntimeException(
330 "readMdSal: Error reading from operational store, Operational Mode Catalog : " + omCatalogIid + " :"
333 networkTransactionService.close();
336 // In other cases, means the mode is a non OpenROADM specific Operational Mode
337 // InstanceIdentifier<SpecificOperationalMode> omCatalogIid = InstanceIdentifier
338 var omCatalogIid = InstanceIdentifier
339 .builder(OperationalModeCatalog.class)
340 .child(SpecificOperationalModes.class)
341 .child(SpecificOperationalMode.class, new SpecificOperationalModeKey(operationalModeId))
344 Optional<SpecificOperationalMode> somOptional = networkTransactionService
345 .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
346 if (somOptional.isPresent()) {
347 speTspOM = somOptional.get();
348 LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", speTspOM);
349 if (speTspOM.getMinRXOsnrTolerance() != null) {
350 rxOsnrdB = speTspOM.getMinRXOsnrTolerance().getValue().doubleValue();
352 penaltiesMap = speTspOM.getPenalties();
354 } catch (InterruptedException | ExecutionException e) {
355 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
356 throw new RuntimeException(
357 "readMdSal: Error reading from operational store, Operational Mode Catalog : " + omCatalogIid + " :"
360 networkTransactionService.close();
363 if (penaltiesMap == null) {
364 LOG.error("Unable to calculate margin as penaltyMap can not be retrieved : Operational mode not populated");
367 HashMap<String, Double> impairments = new HashMap<>();
368 double penalty = getRxTspPenalty(calcCd, ImpairmentType.CDPsNm, penaltiesMap);
369 impairments.put("CDpenalty", penalty);
370 double totalPenalty = penalty;
371 penalty = getRxTspPenalty(calcPmd, ImpairmentType.PMDPs, penaltiesMap);
372 impairments.put("PMD Penalty", penalty);
373 totalPenalty += penalty;
374 penalty = getRxTspPenalty(calcPdl, ImpairmentType.PDLDB, penaltiesMap);
375 impairments.put("PDL penalty", penalty);
376 totalPenalty += penalty;
377 // TODO for Future work since at that time we have no way to calculate the following
378 // parameters,even if penalties are defined in the OpenROADM specifications
380 // impairments.put("Colorless Drop Adjacent Xtalk Penalty", getRxTspPenalty(TBD,
381 // ImpairmentType.ColorlessDropAdjacentChannelCrosstalkGHz, penalitiesMap));
382 // impairments.put("XTalk total Power Penalty", getRxTspPenalty(TBD,
383 // ImpairmentType.CrossTalkTotalPowerDB, penalitiesMap));
384 // impairments.put("Power penalty", getRxTspPenalty(TBD,
385 // ImpairmentType.PowerDBm, penalitiesMap));
386 LOG.info("Penalty resulting from CD, PMD and PDL is {} dB with following contributions {}",
387 totalPenalty, impairments);
388 double margin = calcOsnrdB - totalPenalty - rxOsnrdB;
389 LOG.info("According to RX TSP Specification and calculated impairments Margin is {} dB ", margin);
391 LOG.warn("Negative margin shall result in PCE rejecting the analyzed path");
397 * This generic method is called from getPceRxTspParameters to provide the
398 * Penalties associated with CD, PMD and DGD for Xponder. It scans a penalty
399 * list that includes penalty values corresponding to an interval between an
400 * upper and a lower boundary for each of the above parameters.
402 * @param impairmentType
403 * : the type of impairment (CD/PMD/DGD)
404 * @param calculatedParameter
405 * calculated accumulated value on the line for the impairment
406 * @param penaltiesMap
407 * the global map of penalties retrieved by getPceRxTspParameters
408 * from the Xponder operational mode
410 * @return the penalty associated with accumulated impairment if it is in the
411 * range specified in the table, a value that will lead to reject the
412 * path if this is not the case
415 private double getRxTspPenalty(double calculatedParameter, ImpairmentType impairmentType,
416 Map<PenaltiesKey, Penalties> penalitiesMap) {
417 Penalties penalty = penalitiesMap.values().stream()
418 // We only keep penalties corresponding to the calculated Parameter
419 .filter(val -> val.getParameterAndUnit().getName().equals(impairmentType.getName()))
420 // we sort it according to the comparator (based on up-to-boundary)
421 .sorted(penaltiesComparator)
422 // keep only items for which up to boundary is greater than calculatedParameter
423 .filter(val -> val.getUpToBoundary().doubleValue() >= calculatedParameter)
424 // takes the immediate greater or equal value
425 .findFirst().orElse(null);
426 return penalty == null
427 //means a boundary that is greater than calculatedParameter couldn't be found
428 // Out of specification!
430 // In spec, return penalty associated with calculatedParameter
431 : penalty.getPenaltyValue().getValue().doubleValue();
435 * This method retrieves performance parameters associated with ROADMs and
436 * Amplifiers. It calculates the contribution of the node to the degradation of
437 * the signal for CD, DGD, PDL, and OSNR which is calculated through a
438 * polynomial fit described in the catalog. It finally corrects the accumulated
439 * values for these parameters and return them.
441 * @param catalogNodeType
442 * crossed node path type (ADD/DROP/EXPRESS/AMP)
443 * @param operationalModeId
444 * operational-mode-Id of the Node (OpenROADM only)
446 * accumulated chromatic dispersion across the line
448 * Square of accumulated Group velocity dispersion across the line
450 * Square of the accumulated Polarization Dependant Loss across the
453 * Input power required to calculate OSNR contribution of the node =
456 * Linear Optical Noise to Signal Ratio resulting from the
457 * transmission on the line, that shall include the Non Linear
460 * Interchannel spacing used for correction to calculate OSNR
461 * contribution of the node
463 * @return Impairment, a map that provides corrected values for all calculated
464 * parameters which includes the contribution of the node
465 * (CD/DGD2/PDL2/ONSRLin)
466 * @throws RuntimeException
467 * if operationalModeId is not described in the catalog
470 public Map<String, Double> getPceRoadmAmpParameters(CatalogConstant.CatalogNodeType catalogNodeType,
471 String operationalModeId, double pwrIn, double calcCd, double calcDgd2, double calcPdl2,
472 double calcOnsrLin, double spacing) {
473 //TODO more refactoring need here
474 double pdl2 = calcPdl2;
475 double dgd2 = calcDgd2;
477 double onsrLin = calcOnsrLin;
478 switch (catalogNodeType) {
480 var omCatalogIid = InstanceIdentifier
481 .builder(OperationalModeCatalog.class)
482 .child(OpenroadmOperationalModes.class)
485 .child(AddOpenroadmOperationalMode.class, new AddOpenroadmOperationalModeKey(operationalModeId))
489 networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
490 if (omOptional.isEmpty()) {
491 LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
492 return new HashMap<>();
494 var orAddOM = omOptional.get();
495 LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAddOM);
496 networkTransactionService.close();
498 + Math.pow(10, (-orAddOM.getIncrementalOsnr().getValue().doubleValue()
499 - Math.log10(spacing / 50.0)) / 10.0);
500 cd += orAddOM.getMaxIntroducedCd().doubleValue();
501 pdl2 += Math.pow(orAddOM.getMaxIntroducedPdl().getValue().doubleValue(), 2.0);
502 dgd2 += Math.pow(orAddOM.getMaxIntroducedDgd().doubleValue(), 2.0);
503 } catch (InterruptedException | ExecutionException e) {
505 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
507 throw new RuntimeException(
508 "readMdSal: Error reading from operational store, Operational Mode Catalog : "
509 + omCatalogIid + " :" + e);
511 networkTransactionService.close();
516 var omCatalogIid1 = InstanceIdentifier
517 .builder(OperationalModeCatalog.class)
518 .child(OpenroadmOperationalModes.class)
521 .child(OpenroadmOperationalMode.class, new OpenroadmOperationalModeKey(operationalModeId))
525 networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid1).get();
526 if (omOptional.isEmpty()) {
527 LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
528 return new HashMap<>();
530 var orDropOM = omOptional.get();
531 LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orDropOM);
532 networkTransactionService.close();
533 cd += orDropOM.getMaxIntroducedCd().doubleValue();
534 pdl2 += Math.pow(orDropOM.getMaxIntroducedPdl().getValue().doubleValue(), 2.0);
535 dgd2 += Math.pow(orDropOM.getMaxIntroducedDgd().doubleValue(), 2);
536 onsrLin += Math.pow(10,
537 -(orDropOM.getOsnrPolynomialFit().getA().doubleValue() * Math.pow(pwrIn, 3)
538 + orDropOM.getOsnrPolynomialFit().getB().doubleValue() * Math.pow(pwrIn, 2)
539 + orDropOM.getOsnrPolynomialFit().getC().doubleValue() * pwrIn
540 + orDropOM.getOsnrPolynomialFit().getD().doubleValue()
541 + 10 * Math.log10(spacing / 50.0)) / 10);
542 } catch (InterruptedException | ExecutionException e) {
543 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
545 throw new RuntimeException(
546 "readMdSal: Error reading from operational store, Operational Mode Catalog : "
547 + omCatalogIid1 + " :" + e);
549 networkTransactionService.close();
554 var omCatalogIid2 = InstanceIdentifier
555 .builder(OperationalModeCatalog.class)
556 .child(OpenroadmOperationalModes.class)
558 .child(Express.class)
560 org.opendaylight.yang.gen.v1.http
561 .org.openroadm.operational.mode.catalog.rev211210
562 .operational.mode.roadm.express.parameters.express.OpenroadmOperationalMode.class,
563 new org.opendaylight.yang.gen.v1.http
564 .org.openroadm.operational.mode.catalog.rev211210
565 .operational.mode.roadm.express.parameters.express.OpenroadmOperationalModeKey(
569 var omOptional = networkTransactionService
570 .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid2)
572 if (omOptional.isEmpty()) {
573 LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
574 return new HashMap<>();
576 var orExpressOM = omOptional.get();
577 LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orExpressOM);
578 cd += orExpressOM.getMaxIntroducedCd().doubleValue();
579 pdl2 += Math.pow(orExpressOM.getMaxIntroducedPdl().getValue().doubleValue(), 2.0);
580 dgd2 += Math.pow(orExpressOM.getMaxIntroducedDgd().doubleValue(), 2.0);
581 onsrLin += Math.pow(10,
582 -(orExpressOM.getOsnrPolynomialFit().getA().doubleValue() * Math.pow(pwrIn, 3)
583 + orExpressOM.getOsnrPolynomialFit().getB().doubleValue() * Math.pow(pwrIn, 2)
584 + orExpressOM.getOsnrPolynomialFit().getC().doubleValue() * pwrIn
585 + orExpressOM.getOsnrPolynomialFit().getD().doubleValue()
586 + 10 * Math.log10(spacing / 50.0)) / 10);
587 } catch (InterruptedException | ExecutionException e) {
588 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
590 throw new RuntimeException(
591 "readMdSal: Error reading from operational store, Operational Mode Catalog : "
592 + omCatalogIid2 + " :" + e);
594 networkTransactionService.close();
599 var omCatalogIid3 = InstanceIdentifier
600 .builder(OperationalModeCatalog.class)
601 .child(OpenroadmOperationalModes.class)
602 .child(Amplifiers.class)
603 .child(Amplifier.class)
604 .child(OpenroadmOperationalMode.class, new OpenroadmOperationalModeKey(operationalModeId))
607 var omOptional = networkTransactionService
608 .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid3)
610 if (omOptional.isEmpty()) {
611 LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
612 return new HashMap<>();
614 var orAmpOM = omOptional.get();
615 LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAmpOM);
616 networkTransactionService.close();
617 cd += orAmpOM.getMaxIntroducedCd().doubleValue();
618 pdl2 += Math.pow(orAmpOM.getMaxIntroducedPdl().getValue().doubleValue(), 2.0);
619 dgd2 += Math.pow(orAmpOM.getMaxIntroducedDgd().doubleValue(), 2.0);
620 onsrLin += Math.pow(10,
621 -(orAmpOM.getOsnrPolynomialFit().getA().doubleValue() * Math.pow(pwrIn, 3)
622 + orAmpOM.getOsnrPolynomialFit().getB().doubleValue() * Math.pow(pwrIn, 2)
623 + orAmpOM.getOsnrPolynomialFit().getC().doubleValue() * pwrIn
624 + orAmpOM.getOsnrPolynomialFit().getD().doubleValue()
625 + 10 * Math.log10(spacing / 50.0)) / 10);
626 } catch (InterruptedException | ExecutionException e) {
627 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
629 throw new RuntimeException(
630 "readMdSal: Error reading from operational store, Operational Mode Catalog : "
631 + omCatalogIid3 + " :" + e);
633 networkTransactionService.close();
637 LOG.warn("Unsupported catalogNodeType {}", catalogNodeType);
640 Map<String, Double> impairments = new HashMap<>();
641 impairments.put("CD", cd);
642 impairments.put("DGD2", dgd2);
643 impairments.put("PDL2", pdl2);
644 impairments.put("ONSRLIN", onsrLin);
645 LOG.info("Accumulated CD is {} ps, DGD2 is {} ps and PDL2 is {} dB", cd, Math.sqrt(dgd2), Math.sqrt(pdl2));
646 LOG.info("Resulting OSNR is {} dB", 10 * Math.log10(1 / onsrLin));
651 * Non linear contribution computation.
652 * Public method calculating non linear contribution among the path from
653 * launched power and span length Formula comes from
654 * OpenROADM_OSNR_Calculation_20220610 Tool The resulting contribution shall be
655 * calculated for each fiber span and summed up
656 * @param launchedPowerdB
657 * The power launched in the span (shall account for Optical Distribution
660 * Length of the span in km
662 * OpenROADM power and osnr contribution calculations are based on
663 * spacing between channels : the Media Channel (MC) width
665 * @return nonLinearOnsrContributionLin
666 * The inverse of the NL OSNR contribution converted from dB to linear value
668 public double calculateNLonsrContribution(double launchedPowerdB, double spanLength, double spacing) {
669 double constanteC0 = 0 ;
670 if (spacing > 162.5) {
671 constanteC0 = CatalogConstant.NLCONSTANTC0GT1625;
672 } else if (spacing > 112.5) {
673 constanteC0 = CatalogConstant.NLCONSTANTC0UPTO1625;
674 } else if (spacing > 100.0) {
675 constanteC0 = CatalogConstant.NLCONSTANTC0UPTO1125;
676 } else if (spacing > 87.5) {
677 constanteC0 = CatalogConstant.NLCONSTANTC0UPTO1000;
679 constanteC0 = CatalogConstant.NLCONSTANTC0UPTO875;
681 double nonLinearOnsrContributionLinDb = launchedPowerdB * CatalogConstant.NLCONSTANTC1
682 + constanteC0 + CatalogConstant.NLCONSTANTCE * Math.exp(CatalogConstant.NLCONSTANTEX * spanLength);
683 LOG.info(" OSNR Non Linear contribution is {} dB", nonLinearOnsrContributionLinDb);
684 return Math.pow(10.0, -nonLinearOnsrContributionLinDb / 10);