Refactor few LOG messages management
[transportpce.git] / common / src / main / java / org / opendaylight / transportpce / common / catalog / CatalogUtils.java
index 0fab6def1715489f97279530ca061cfb1560f279..f4a807f8c7edd5c25e5d276494e0464ccde6f7cf 100644 (file)
@@ -8,12 +8,14 @@
 package org.opendaylight.transportpce.common.catalog;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.transportpce.common.StringConstants;
 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.link.types.rev191129.RatioDB;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.ImpairmentType;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.amplifier.parameters.Amplifier;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.catalog.OpenroadmOperationalModes;
@@ -51,6 +53,23 @@ import org.slf4j.LoggerFactory;
 public class CatalogUtils {
 
     private static final Logger LOG = LoggerFactory.getLogger(CatalogUtils.class);
+
+    private static final String OPMODE_MISMATCH_MSG =
+        "Operational Mode {} passed to getPceRoadmAmpParameters does not correspond to an OpenROADM mode"
+        + "Parameters for amplifier and/or ROADMs can not be derived from specific-operational-modes.";
+    private static final Map<CatalogConstant.CatalogNodeType, String> CATALOGNODETYPE_OPERATIONMODEID_MAP = Map.of(
+        CatalogConstant.CatalogNodeType.ADD, CatalogConstant.MWWRCORE,
+        CatalogConstant.CatalogNodeType.DROP, CatalogConstant.MWWRCORE,
+        CatalogConstant.CatalogNodeType.EXPRESS, CatalogConstant.MWMWCORE,
+        CatalogConstant.CatalogNodeType.AMP, CatalogConstant.MWISTANDARD);
+    private static final Map<String, String> TSP_DEFAULT_OM_MAP = Map.of(
+        StringConstants.SERVICE_TYPE_100GE_T, CatalogConstant.ORW100GSC,
+        StringConstants.SERVICE_TYPE_OTU4, CatalogConstant.ORW100GSC,
+        StringConstants.SERVICE_TYPE_OTUC2,  CatalogConstant.ORW200GOFEC316GBD,
+        StringConstants.SERVICE_TYPE_OTUC3, CatalogConstant.ORW300GOFEC631GBD,
+        StringConstants.SERVICE_TYPE_OTUC4, CatalogConstant.ORW400GOFEC631GBD,
+        StringConstants.SERVICE_TYPE_400GE, CatalogConstant.ORW400GOFEC631GBD);
+
     private final PenaltiesComparator penaltiesComparator = new PenaltiesComparator();
     private NetworkTransactionService networkTransactionService;
 
@@ -71,40 +90,18 @@ public class CatalogUtils {
      */
     public String getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType catalogNodeType,
             String serviceType) {
-        String operationalModeId = "";
-
-        switch (catalogNodeType) {
-            case ADD:
-            case DROP:
-                operationalModeId = CatalogConstant.MWWRCORE;
-                break;
-            case EXPRESS:
-                operationalModeId = CatalogConstant.MWMWCORE;
-                break;
-            case AMP:
-                operationalModeId = CatalogConstant.MWISTANDARD;
-                break;
-            case TSP:
-                if (StringConstants.SERVICE_TYPE_100GE_T.contentEquals(serviceType)
-                        || StringConstants.SERVICE_TYPE_OTU4.contentEquals(serviceType)) {
-                    operationalModeId = CatalogConstant.ORW100GSC;
-                }
-                if (StringConstants.SERVICE_TYPE_OTUC2.contentEquals(serviceType)) {
-                    operationalModeId = CatalogConstant.ORW200GOFEC316GBD;
-                }
-                if (StringConstants.SERVICE_TYPE_OTUC3.contentEquals(serviceType)) {
-                    operationalModeId = CatalogConstant.ORW300GOFEC631GBD;
-                }
-                if ((StringConstants.SERVICE_TYPE_OTUC4.contentEquals(serviceType))
-                        || (StringConstants.SERVICE_TYPE_400GE.contentEquals(serviceType))) {
-                    operationalModeId = CatalogConstant.ORW400GOFEC631GBD;
-                }
-                break;
-            default:
-                LOG.warn("Unsupported catalogNodeType {}", catalogNodeType);
-                break;
+        if (CATALOGNODETYPE_OPERATIONMODEID_MAP.containsKey(catalogNodeType)) {
+            return CATALOGNODETYPE_OPERATIONMODEID_MAP.get(catalogNodeType);
+        }
+        if (!catalogNodeType.equals(CatalogConstant.CatalogNodeType.TSP)) {
+            LOG.warn("Unsupported catalogNodeType {}", catalogNodeType);
+            return "";
         }
-        return operationalModeId;
+        if (!TSP_DEFAULT_OM_MAP.containsKey(serviceType)) {
+            LOG.warn("Unsupported serviceType {} for TSP catalogNodeType", serviceType);
+            return "";
+        }
+        return TSP_DEFAULT_OM_MAP.get(serviceType);
     }
 
     /**
@@ -120,11 +117,8 @@ public class CatalogUtils {
      */
 
     public double getPceTxTspChannelSpacing(String operationalModeId) {
-        double spacing = 0.0;
-        double rolloff = 0.2;
-        XponderPluggableOpenroadmOperationalMode orTspOM = null;
-        SpecificOperationalMode speTspOM = null;
-
+        double baudRate;
+        double maxRollOff;
         if (operationalModeId.startsWith("OR")) {
             InstanceIdentifier<XponderPluggableOpenroadmOperationalMode> omCatalogIid = InstanceIdentifier
                 .builder(OperationalModeCatalog.class)
@@ -134,40 +128,21 @@ public class CatalogUtils {
                     new XponderPluggableOpenroadmOperationalModeKey(operationalModeId))
                 .build();
             try {
-                Optional<XponderPluggableOpenroadmOperationalMode> omOptional = networkTransactionService
-                    .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
-                if (omOptional.isPresent()) {
-                    orTspOM = omOptional.get();
-                    if ((orTspOM.getMaxRollOff() == null) || (orTspOM.getMaxRollOff().doubleValue() == 0)) {
-                        if (CatalogConstant.ORW100GSC.contentEquals(operationalModeId)) {
-                            spacing = 50.0;
-                            LOG.info("Operational Mode {} associated channel spacing is {}",
-                                operationalModeId, spacing);
-
-                        } else {
-                            spacing = (Math.ceil(
-                                orTspOM.getBaudRate().doubleValue() * (1 + 0.2) / 12.5)) * 12.5;
-                            LOG.warn("Did not succeed in retrieving rolloff factor from Operational Mode {},"
-                                + " used default value of 0.2  --> Please check operational mode catalog,"
-                                + " Rolloff factor is a mandatory parameter", operationalModeId);
-                        }
-                    } else {
-                        spacing = (Math.ceil(
-                            orTspOM.getBaudRate().doubleValue() * (1 + orTspOM.getMaxRollOff().doubleValue()) / 12.5))
-                            * 12.5;
-                    }
-                    LOG.info("Operational Mode {} associated channel spacing is {}",
-                        operationalModeId, spacing);
+                Optional<XponderPluggableOpenroadmOperationalMode> omOptional =
+                    networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
+                if (omOptional.isEmpty()) {
+                    LOG.error("readMdSal: Error reading Operational Mode Catalog {} , empty list", omCatalogIid);
+                    return 0.0;
                 }
+                XponderPluggableOpenroadmOperationalMode orTspOM = omOptional.get();
+                maxRollOff = orTspOM.getMaxRollOff() == null ? 0 : orTspOM.getMaxRollOff().doubleValue();
+                baudRate = orTspOM.getBaudRate().doubleValue();
             } catch (InterruptedException | ExecutionException e) {
                 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
-                throw new RuntimeException(
-                    "Operational mode not populated in Catalog : "
-                        + omCatalogIid + " :" + e);
+                throw new RuntimeException("Operational mode not populated in Catalog : " + omCatalogIid + " :" + e);
             } finally {
                 networkTransactionService.close();
             }
-
         } else {
             // In other cases, means the mode is a non OpenROADM specific Operational Mode
             InstanceIdentifier<SpecificOperationalMode> omCatalogIid = InstanceIdentifier
@@ -176,32 +151,34 @@ public class CatalogUtils {
                 .child(SpecificOperationalMode.class, new SpecificOperationalModeKey(operationalModeId))
                 .build();
             try {
-                var somOptional = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid)
-                    .get();
-                if (somOptional.isPresent()) {
-                    speTspOM = somOptional.get();
-                    if ((speTspOM.getMaxRollOff() == null) || (speTspOM.getMaxRollOff().doubleValue() == 0)) {
-                        spacing = (Math.ceil(speTspOM.getBaudRate().doubleValue() * (1 + 0.2) / 12.5)) * 12.5;
-                        LOG.warn("Did not succeed in retrieving rolloff factor from Operational Mode {},"
-                            + " used default value of 0.2  --> Please check operational mode catalog,"
-                            + " Rolloff factor is a mandatory parameter", operationalModeId);
-                    } else {
-                        spacing = (Math.ceil(
-                            speTspOM.getBaudRate().doubleValue() * (1 + speTspOM.getMaxRollOff().doubleValue()) / 12.5))
-                            * 12.5;
-                    }
-                    LOG.info("Operational Mode {} associated channel spacing is {}",
-                        operationalModeId, spacing);
+                var somOptional =
+                    networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
+                if (somOptional.isEmpty()) {
+                    LOG.error("readMdSal: Error reading Operational Mode Catalog {} , empty list", omCatalogIid);
+                    return 0.0;
                 }
+                SpecificOperationalMode speTspOM = somOptional.get();
+                maxRollOff = speTspOM.getMaxRollOff() == null ? 0 : speTspOM.getMaxRollOff().doubleValue();
+                baudRate = speTspOM.getBaudRate().doubleValue();
             } catch (InterruptedException | ExecutionException e) {
                 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
-                throw new RuntimeException(
-                    "Operational mode not populated in Catalog : "
-                        + omCatalogIid + " :" + e);
+                throw new RuntimeException("Operational mode not populated in Catalog : " + omCatalogIid + " :" + e);
             } finally {
                 networkTransactionService.close();
             }
         }
+        if (maxRollOff == 0) {
+            if (CatalogConstant.ORW100GSC.contentEquals(operationalModeId)) {
+            // OR 100G SCFEC is the only case where rolloff factor is not mandatory in the catalog
+                LOG.info("Operational Mode {} associated channel spacing is 50.0", operationalModeId);
+                return 50.0;
+            }
+            LOG.warn("Missing rolloff factor (mandatory in Catalog) from Operational Mode {}: use default=0.2",
+                operationalModeId);
+            maxRollOff = 0.2;
+        }
+        double spacing = 12.5 * Math.ceil(baudRate * (1 + maxRollOff) / 12.5);
+        LOG.info("Operational Mode {} associated channel spacing is {}", operationalModeId, spacing);
         return spacing;
     }
 
@@ -222,7 +199,8 @@ public class CatalogUtils {
         double txOnsrLin = 0.0;
         XponderPluggableOpenroadmOperationalMode orTspOM = null;
         SpecificOperationalMode speTspOM = null;
-
+        RatioDB minOOBOsnrSingleChannelValue;
+        RatioDB minOOBOsnrMultiChannelValue;
         if (operationalModeId.startsWith("OR")) {
             InstanceIdentifier<XponderPluggableOpenroadmOperationalMode> omCatalogIid = InstanceIdentifier
                 .builder(OperationalModeCatalog.class)
@@ -232,38 +210,31 @@ public class CatalogUtils {
                     new XponderPluggableOpenroadmOperationalModeKey(operationalModeId))
                 .build();
             try {
-                Optional<XponderPluggableOpenroadmOperationalMode> omOptional = networkTransactionService
-                    .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
-                if (omOptional.isPresent()) {
-                    orTspOM = omOptional.get();
-                    LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orTspOM);
-                    TXOOBOsnrKey key = new TXOOBOsnrKey(addDropMuxOperationalModeId);
-                    if (orTspOM.getMinTXOsnr() != null) {
-                        txOnsrLin = 1.0 / (Math.pow(10.0, (orTspOM.getMinTXOsnr().getValue().doubleValue() / 10.0)));
-                    }
-                    if (orTspOM.nonnullTXOOBOsnr().get(key) != null
-                            && orTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrSingleChannelValue() != null) {
-                        // To 1/(Xponder Min TX OSNR lin) Add 1/(Xponder TX OOB OSNR Single channel lin)
-                        txOnsrLin = txOnsrLin + 1.0 / (Math.pow(10.0, (orTspOM.nonnullTXOOBOsnr().get(key)
-                            .getMinOOBOsnrSingleChannelValue().getValue().doubleValue() / 10.0)));
-                    }
-                    if (orTspOM.getTXOOBOsnr() != null && orTspOM.nonnullTXOOBOsnr().get(key)
-                            .getMinOOBOsnrMultiChannelValue() != null) {
-                        // To resulting 1/(OSNR lin) Add 1/(Xponder TX OOB OSNR Multi channel lin)
-                        // contribution
-                        txOnsrLin = txOnsrLin + 1.0 / (Math.pow(10.0, (orTspOM.nonnullTXOOBOsnr().get(key)
-                            .getMinOOBOsnrMultiChannelValue().getValue().doubleValue() / 10.0)));
-                    }
+                Optional<XponderPluggableOpenroadmOperationalMode> omOptional =
+                    networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
+                if (omOptional.isEmpty()) {
+                    LOG.error("readMdSal: Error reading Operational Mode Catalog {} , empty list", omCatalogIid);
+                    return 0.0;
                 }
+                orTspOM = omOptional.get();
+                LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orTspOM);
+                TXOOBOsnrKey key = new TXOOBOsnrKey(addDropMuxOperationalModeId);
+                if (orTspOM.getMinTXOsnr() != null) {
+                    txOnsrLin = 1.0 / Math.pow(10.0, orTspOM.getMinTXOsnr().getValue().doubleValue() / 10.0);
+                }
+                if (orTspOM.nonnullTXOOBOsnr().get(key) == null) {
+                    return txOnsrLin;
+                }
+                minOOBOsnrSingleChannelValue = orTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrSingleChannelValue();
+                minOOBOsnrMultiChannelValue =  orTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrMultiChannelValue();
             } catch (InterruptedException | ExecutionException e) {
                 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
                 throw new RuntimeException(
-                    "readMdSal: Error reading from operational store, Operational Mode Catalog : " + omCatalogIid + " :"
-                        + e);
+                    "readMdSal: Error reading from operational store, Operational Mode Catalog : "
+                        + omCatalogIid + " :" + e);
             } finally {
                 networkTransactionService.close();
             }
-
         } else {
             // In other cases, means the mode is a non OpenROADM specific Operational Mode
             InstanceIdentifier<SpecificOperationalMode> omCatalogIid = InstanceIdentifier
@@ -272,30 +243,23 @@ public class CatalogUtils {
                 .child(SpecificOperationalMode.class, new SpecificOperationalModeKey(operationalModeId))
                 .build();
             try {
-                var somOptional = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid)
-                    .get();
-                if (somOptional.isPresent()) {
-                    speTspOM = somOptional.get();
-                    LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", speTspOM);
-                    TXOOBOsnrKey key = new TXOOBOsnrKey(addDropMuxOperationalModeId);
-                    if (speTspOM.getMinTXOsnr() != null) {
-                        txOnsrLin = 1.0 / (Math.pow(10.0, (speTspOM.getMinTXOsnr().getValue().doubleValue() / 10.0)));
-                    }
-                    if (speTspOM.nonnullTXOOBOsnr().get(key) != null
-                            && speTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrSingleChannelValue() != null) {
-                        // Add to 1/(Transponder Min TX OSNR lin) 1/(Transponder TX OOB OSNR Single
-                        // channel lin)
-                        txOnsrLin = txOnsrLin + 1.0 / (Math.pow(10.0, (speTspOM.nonnullTXOOBOsnr().get(key)
-                            .getMinOOBOsnrSingleChannelValue().getValue().doubleValue() / 10.0)));
-                    }
-                    if (speTspOM.nonnullTXOOBOsnr().get(key) != null
-                            && speTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrMultiChannelValue() != null) {
-                        // Add to resulting 1/(OSNR lin) 1/(Transponder TX OOB OSNR Multi channel lin)
-                        // contribution
-                        txOnsrLin = txOnsrLin + 1.0 / (Math.pow(10.0, (speTspOM.nonnullTXOOBOsnr().get(key)
-                            .getMinOOBOsnrMultiChannelValue().getValue().doubleValue() / 10.0)));
-                    }
+                var somOptional =
+                    networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
+                if (somOptional.isEmpty()) {
+                    LOG.error("readMdSal: Error reading Operational Mode Catalog {} , empty list", omCatalogIid);
+                    return 0.0;
+                }
+                speTspOM = somOptional.get();
+                LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", speTspOM);
+                TXOOBOsnrKey key = new TXOOBOsnrKey(addDropMuxOperationalModeId);
+                if (speTspOM.getMinTXOsnr() != null) {
+                    txOnsrLin = 1.0 / Math.pow(10.0, speTspOM.getMinTXOsnr().getValue().doubleValue() / 10.0);
                 }
+                if (speTspOM.nonnullTXOOBOsnr().get(key) == null) {
+                    return txOnsrLin;
+                }
+                minOOBOsnrSingleChannelValue = speTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrSingleChannelValue();
+                minOOBOsnrMultiChannelValue = speTspOM.nonnullTXOOBOsnr().get(key).getMinOOBOsnrMultiChannelValue();
             } catch (InterruptedException | ExecutionException e) {
                 LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist", omCatalogIid);
                 throw new RuntimeException(
@@ -305,6 +269,12 @@ public class CatalogUtils {
                 networkTransactionService.close();
             }
         }
+        if (minOOBOsnrSingleChannelValue != null) {
+            txOnsrLin += 1.0 / Math.pow(10.0, minOOBOsnrSingleChannelValue.getValue().doubleValue() / 10.0);
+        }
+        if (minOOBOsnrMultiChannelValue != null) {
+            txOnsrLin += 1.0 / Math.pow(10.0, minOOBOsnrMultiChannelValue.getValue().doubleValue() / 10.0);
+        }
         return txOnsrLin;
     }
 
@@ -332,11 +302,7 @@ public class CatalogUtils {
      */
     public double getPceRxTspParameters(String operationalModeId, double calcCd, double calcPmd,
             double calcPdl, double calcOsnrdB) {
-        HashMap<String, Double> impairments = new HashMap<>();
-        double totalPenalty = 0.0;
-        double penalty ;
         double rxOsnrdB = 0.0;
-        double margin = -9999.9;
         XponderPluggableOpenroadmOperationalMode orTspOM = null;
         SpecificOperationalMode speTspOM = null;
         Map<PenaltiesKey, Penalties> penaltiesMap = null;
@@ -395,34 +361,35 @@ public class CatalogUtils {
                 networkTransactionService.close();
             }
         }
-        if (penaltiesMap != null) {
-            penalty = getRxTspPenalty(calcCd, ImpairmentType.CDPsNm, penaltiesMap);
-            impairments.put("CDpenalty", penalty);
-            totalPenalty = totalPenalty + penalty;
-            penalty = getRxTspPenalty(calcPmd, ImpairmentType.PMDPs, penaltiesMap);
-            impairments.put("PMD Penalty", penalty);
-            totalPenalty = totalPenalty + penalty;
-            penalty = getRxTspPenalty(calcPdl, ImpairmentType.PDLDB, penaltiesMap);
-            impairments.put("PDL penalty", penalty);
-            totalPenalty = totalPenalty + penalty;
-            // For Future work since at that time we have no way to calculate the following
-            // parameters,even if penalties are defined in the OpenROADM specifications
-            //
-            // impairments.put("Colorless Drop Adjacent Xtalk Penalty", getRxTspPenalty(TBD,
-            // ImpairmentType.ColorlessDropAdjacentChannelCrosstalkGHz, penalitiesMap));
-            // impairments.put("XTalk total Power Penalty", getRxTspPenalty(TBD,
-            // ImpairmentType.CrossTalkTotalPowerDB, penalitiesMap));
-            // impairments.put("Power penalty", getRxTspPenalty(TBD,
-            // ImpairmentType.PowerDBm, penalitiesMap));
-            LOG.info("Penalty resulting from CD, PMD and PDL is {} dB with following contributions {}",
-                totalPenalty, impairments);
-            margin = calcOsnrdB - totalPenalty - rxOsnrdB;
-            LOG.info("According to RX TSP Specification and calculated impairments Margin is {} dB ", margin);
-            if (margin < 0) {
-                LOG.info("Negative margin shall result in PCE rejecting the analyzed path");
-            }
-        } else {
-            LOG.info("Unable to calculate margin as penaltyMap can not be retrieved : Operational mode not populated");
+        if (penaltiesMap == null) {
+            LOG.error("Unable to calculate margin as penaltyMap can not be retrieved : Operational mode not populated");
+            return -9999.9;
+        }
+        HashMap<String, Double> impairments = new HashMap<>();
+        double penalty = getRxTspPenalty(calcCd, ImpairmentType.CDPsNm, penaltiesMap);
+        impairments.put("CDpenalty", penalty);
+        double totalPenalty = penalty;
+        penalty = getRxTspPenalty(calcPmd, ImpairmentType.PMDPs, penaltiesMap);
+        impairments.put("PMD Penalty", penalty);
+        totalPenalty += penalty;
+        penalty = getRxTspPenalty(calcPdl, ImpairmentType.PDLDB, penaltiesMap);
+        impairments.put("PDL penalty", penalty);
+        totalPenalty += penalty;
+        // TODO for Future work since at that time we have no way to calculate the following
+        // parameters,even if penalties are defined in the OpenROADM specifications
+        //
+        // impairments.put("Colorless Drop Adjacent Xtalk Penalty", getRxTspPenalty(TBD,
+        // ImpairmentType.ColorlessDropAdjacentChannelCrosstalkGHz, penalitiesMap));
+        // impairments.put("XTalk total Power Penalty", getRxTspPenalty(TBD,
+        // ImpairmentType.CrossTalkTotalPowerDB, penalitiesMap));
+        // impairments.put("Power penalty", getRxTspPenalty(TBD,
+        // ImpairmentType.PowerDBm, penalitiesMap));
+        LOG.info("Penalty resulting from CD, PMD and PDL is {} dB with following contributions {}",
+            totalPenalty, impairments);
+        double margin = calcOsnrdB - totalPenalty - rxOsnrdB;
+        LOG.info("According to RX TSP Specification and calculated impairments Margin is {} dB ", margin);
+        if (margin < 0) {
+            LOG.warn("Negative margin shall result in PCE rejecting the analyzed path");
         }
         return margin;
     }
@@ -447,7 +414,7 @@ public class CatalogUtils {
      */
 
     private double getRxTspPenalty(double calculatedParameter, ImpairmentType impairmentType,
-        Map<PenaltiesKey, Penalties> penalitiesMap) {
+            Map<PenaltiesKey, Penalties> penalitiesMap) {
         Penalties penalty = penalitiesMap.values().stream()
             // We only keep penalties corresponding to the calculated Parameter
             .filter(val -> val.getParameterAndUnit().getName().equals(impairmentType.getName()))
@@ -457,13 +424,13 @@ public class CatalogUtils {
             .filter(val -> val.getUpToBoundary().doubleValue() >= calculatedParameter)
             // takes the immediate greater or equal value
             .findFirst().orElse(null);
-
         if (penalty == null) {
             //means a boundary that is greater than calculatedParameter couldn't be found
             // Out of specification!
             return 9999.9;
         }
         // In spec, return penalty associated with calculatedParameter
+        LOG.info("Penalty for {} is {} dB", impairmentType, penalty.getPenaltyValue().getValue().doubleValue());
         return penalty.getPenaltyValue().getValue().doubleValue();
     }
 
@@ -478,17 +445,17 @@ public class CatalogUtils {
      *            crossed node path type (ADD/DROP/EXPRESS/AMP)
      * @param operationalModeId
      *            operational-mode-Id of the Node (OpenROADM only)
-     * @param calcCd
+     * @param cd
      *            accumulated chromatic dispersion across the line
-     * @param calcDgd2
+     * @param dgd2
      *            Square of accumulated Group velocity dispersion across the line
-     * @param calcPdl2
+     * @param pdl2
      *            Square of the accumulated Polarization Dependant Loss across the
      *            line
      * @param pwrIn
      *            Input power required to calculate OSNR contribution of the node =
      *            f(pwrIn)
-     * @param calcOnsrLin
+     * @param onsrLin
      *            Linear Optical Noise to Signal Ratio resulting from the
      *            transmission on the line, that shall include the Non Linear
      *            contribution
@@ -504,16 +471,12 @@ public class CatalogUtils {
      */
 
     public Map<String, Double> getPceRoadmAmpParameters(CatalogConstant.CatalogNodeType catalogNodeType,
-        String operationalModeId, double pwrIn, double calcCd, double calcDgd2, double calcPdl2,
-        double calcOnsrLin, double spacing) {
-
-        Map<String, Double> impairments = new HashMap<>();
-        double pdl2 = calcPdl2;
-        double dgd2 = calcDgd2;
-        double cd = calcCd;
-        double onsrLin = calcOnsrLin;
-        boolean supportedMode = true;
-
+            String operationalModeId, double pwrIn, double cd, double dgd2, double pdl2,
+            double onsrLin, double spacing) {
+        double maxIntroducedCd;
+        double maxIntroducedPdl;
+        double maxIntroducedDgd;
+        List<Double> osnrPolynomialFits;
         switch (catalogNodeType) {
             case ADD:
                 var omCatalogIid = InstanceIdentifier
@@ -524,21 +487,19 @@ public class CatalogUtils {
                     .child(AddOpenroadmOperationalMode.class, new AddOpenroadmOperationalModeKey(operationalModeId))
                     .build();
                 try {
-                    var omOptional = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION,
-                        omCatalogIid).get();
-                    if (omOptional.isPresent()) {
-                        var orAddOM = omOptional.get();
-                        LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAddOM);
-                        networkTransactionService.close();
-                        onsrLin = onsrLin
-                            + Math.pow(10, (-orAddOM.getIncrementalOsnr().getValue().doubleValue()
-                            - Math.log10(spacing / 50.0)) / 10.0);
-                        cd = cd + orAddOM.getMaxIntroducedCd().doubleValue();
-                        pdl2 = pdl2 + Math.pow(orAddOM.getMaxIntroducedPdl().getValue().doubleValue(), 2.0);
-                        dgd2 = dgd2 + Math.pow(orAddOM.getMaxIntroducedDgd().doubleValue(), 2.0);
-                    } else {
-                        supportedMode = false;
+                    var omOptional =
+                        networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
+                    if (omOptional.isEmpty()) {
+                        LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
+                        return new HashMap<>();
                     }
+                    var orAddOM = omOptional.get();
+                    LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAddOM);
+                    networkTransactionService.close();
+                    maxIntroducedCd = orAddOM.getMaxIntroducedCd().doubleValue();
+                    maxIntroducedPdl = orAddOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    maxIntroducedDgd = orAddOM.getMaxIntroducedDgd().doubleValue();
+                    osnrPolynomialFits = List.of(orAddOM.getIncrementalOsnr().getValue().doubleValue());
                 } catch (InterruptedException | ExecutionException e) {
                     onsrLin = 1;
                     LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
@@ -560,28 +521,24 @@ public class CatalogUtils {
                     .child(OpenroadmOperationalMode.class, new OpenroadmOperationalModeKey(operationalModeId))
                     .build();
                 try {
-                    var omOptional = networkTransactionService
-                        .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid1)
-                        .get();
-                    if (omOptional.isPresent()) {
-                        var orDropOM = omOptional.get();
-                        LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orDropOM);
-                        networkTransactionService.close();
-                        cd = cd + orDropOM.getMaxIntroducedCd().doubleValue();
-                        pdl2 = pdl2 + Math.pow(orDropOM.getMaxIntroducedPdl().getValue().doubleValue(), 2.0);
-                        dgd2 = dgd2 + Math.pow(orDropOM.getMaxIntroducedDgd().doubleValue(), 2);
-                        onsrLin = onsrLin + Math.pow(10,
-                            -(orDropOM.getOsnrPolynomialFit().getA().doubleValue() * Math.pow(pwrIn, 3)
-                                + orDropOM.getOsnrPolynomialFit().getB().doubleValue() * Math.pow(pwrIn, 2)
-                                + orDropOM.getOsnrPolynomialFit().getC().doubleValue() * pwrIn
-                                + orDropOM.getOsnrPolynomialFit().getD().doubleValue()
-                                + 10 * Math.log10(spacing / 50.0)) / 10);
-                    } else {
-                        supportedMode = false;
+                    var omOptional =
+                        networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid1).get();
+                    if (omOptional.isEmpty()) {
+                        LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
+                        return new HashMap<>();
                     }
+                    var orDropOM = omOptional.get();
+                    LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orDropOM);
+                    networkTransactionService.close();
+                    maxIntroducedCd = orDropOM.getMaxIntroducedCd().doubleValue();
+                    maxIntroducedPdl = orDropOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    maxIntroducedDgd = orDropOM.getMaxIntroducedDgd().doubleValue();
+                    osnrPolynomialFits = List.of(
+                        orDropOM.getOsnrPolynomialFit().getD().doubleValue(),
+                        orDropOM.getOsnrPolynomialFit().getC().doubleValue(),
+                        orDropOM.getOsnrPolynomialFit().getB().doubleValue(),
+                        orDropOM.getOsnrPolynomialFit().getA().doubleValue());
                 } catch (InterruptedException | ExecutionException e) {
-                    onsrLin = 1;
-                    supportedMode = false;
                     LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
                         omCatalogIid1);
                     throw new RuntimeException(
@@ -600,36 +557,32 @@ public class CatalogUtils {
                     .child(Express.class)
                     .child(
                         org.opendaylight.yang.gen.v1.http
-                        .org.openroadm.operational.mode.catalog.rev211210
-                        .operational.mode.roadm.express.parameters.express.OpenroadmOperationalMode.class,
+                            .org.openroadm.operational.mode.catalog.rev211210
+                            .operational.mode.roadm.express.parameters.express.OpenroadmOperationalMode.class,
                         new org.opendaylight.yang.gen.v1.http
-                        .org.openroadm.operational.mode.catalog.rev211210
-                        .operational.mode.roadm.express.parameters.express.OpenroadmOperationalModeKey(
-                            operationalModeId))
+                            .org.openroadm.operational.mode.catalog.rev211210
+                            .operational.mode.roadm.express.parameters.express.OpenroadmOperationalModeKey(
+                                operationalModeId))
                     .build();
                 try {
                     var omOptional = networkTransactionService
                         .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid2)
                         .get();
-                    if (omOptional.isPresent()) {
-                        var orExpressOM = omOptional.get();
-                        LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}",
-                            orExpressOM);
-                        cd = cd + orExpressOM.getMaxIntroducedCd().doubleValue();
-                        pdl2 = pdl2 + Math.pow(orExpressOM.getMaxIntroducedPdl().getValue().doubleValue(), 2.0);
-                        dgd2 = dgd2 + Math.pow(orExpressOM.getMaxIntroducedDgd().doubleValue(), 2.0);
-                        onsrLin = onsrLin + Math.pow(10,
-                            -(orExpressOM.getOsnrPolynomialFit().getA().doubleValue() * Math.pow(pwrIn, 3)
-                                + orExpressOM.getOsnrPolynomialFit().getB().doubleValue() * Math.pow(pwrIn, 2)
-                                + orExpressOM.getOsnrPolynomialFit().getC().doubleValue() * pwrIn
-                                + orExpressOM.getOsnrPolynomialFit().getD().doubleValue()
-                                + 10 * Math.log10(spacing / 50.0)) / 10);
-                    } else {
-                        supportedMode = false;
+                    if (omOptional.isEmpty()) {
+                        LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
+                        return new HashMap<>();
                     }
+                    var orExpressOM = omOptional.get();
+                    LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orExpressOM);
+                    maxIntroducedCd = orExpressOM.getMaxIntroducedCd().doubleValue();
+                    maxIntroducedPdl = orExpressOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    maxIntroducedDgd = orExpressOM.getMaxIntroducedDgd().doubleValue();
+                    osnrPolynomialFits = List.of(
+                        orExpressOM.getOsnrPolynomialFit().getD().doubleValue(),
+                        orExpressOM.getOsnrPolynomialFit().getC().doubleValue(),
+                        orExpressOM.getOsnrPolynomialFit().getB().doubleValue(),
+                        orExpressOM.getOsnrPolynomialFit().getA().doubleValue());
                 } catch (InterruptedException | ExecutionException e) {
-                    onsrLin = 1;
-                    supportedMode = false;
                     LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
                         omCatalogIid2);
                     throw new RuntimeException(
@@ -652,26 +605,22 @@ public class CatalogUtils {
                     var omOptional = networkTransactionService
                         .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid3)
                         .get();
-                    if (omOptional.isPresent()) {
-                        var orAmpOM = omOptional.get();
-                        LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAmpOM);
-                        networkTransactionService.close();
-                        cd = cd + orAmpOM.getMaxIntroducedCd().doubleValue();
-                        pdl2 = pdl2 + Math.pow(orAmpOM.getMaxIntroducedPdl().getValue().doubleValue(), 2.0);
-                        dgd2 = dgd2 + Math.pow(orAmpOM.getMaxIntroducedDgd().doubleValue(), 2.0);
-                        onsrLin = onsrLin + Math.pow(10,
-                            -(orAmpOM.getOsnrPolynomialFit().getA().doubleValue() * Math.pow(pwrIn, 3)
-                                + orAmpOM.getOsnrPolynomialFit().getB().doubleValue() * Math.pow(pwrIn, 2)
-                                + orAmpOM.getOsnrPolynomialFit().getC().doubleValue() * pwrIn
-                                + orAmpOM.getOsnrPolynomialFit().getD().doubleValue()
-                                + 10 * Math.log10(spacing / 50.0)) / 10);
-
-                    } else {
-                        supportedMode = false;
+                    if (omOptional.isEmpty()) {
+                        LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
+                        return new HashMap<>();
                     }
+                    var orAmpOM = omOptional.get();
+                    LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAmpOM);
+                    networkTransactionService.close();
+                    maxIntroducedCd = orAmpOM.getMaxIntroducedCd().doubleValue();
+                    maxIntroducedPdl = orAmpOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    maxIntroducedDgd = orAmpOM.getMaxIntroducedDgd().doubleValue();
+                    osnrPolynomialFits = List.of(
+                        orAmpOM.getOsnrPolynomialFit().getD().doubleValue(),
+                        orAmpOM.getOsnrPolynomialFit().getC().doubleValue(),
+                        orAmpOM.getOsnrPolynomialFit().getB().doubleValue(),
+                        orAmpOM.getOsnrPolynomialFit().getA().doubleValue());
                 } catch (InterruptedException | ExecutionException e) {
-                    onsrLin = 1;
-                    supportedMode = false;
                     LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
                         omCatalogIid3);
                     throw new RuntimeException(
@@ -682,25 +631,44 @@ public class CatalogUtils {
                 }
                 break;
             default:
-                LOG.warn("Unsupported catalogNodeType {}", catalogNodeType);
-                break;
+                LOG.error("Unsupported catalogNodeType {}", catalogNodeType);
+                return new HashMap<>();
         }
-
-        if (supportedMode) {
-            impairments.put("CD", cd);
-            impairments.put("DGD2", dgd2);
-            impairments.put("PDL2", pdl2);
-            impairments.put("ONSRLIN", onsrLin);
-
-            LOG.info("Accumulated CD is {} ps, DGD2 is {} ps and PDL2 is {} dB", cd, Math.sqrt(dgd2), Math.sqrt(pdl2));
-            LOG.info("Resulting OSNR is {} dB", 10 * Math.log10(1 / onsrLin));
-
-        } else {
-            LOG.error("Operational Mode {} passed to getPceRoadmAmpParameters does not correspond to an OpenROADM mode"
-                + "Parameters for amplifier and/or ROADMs can not be derived from specific-operational-modes.",
-                operationalModeId);
+        cd += maxIntroducedCd;
+        pdl2 += Math.pow(maxIntroducedPdl, 2.0);
+        dgd2 += Math.pow(maxIntroducedDgd, 2.0);
+        double pwrFact = 1;
+        double contrib = 10 * Math.log10(spacing / 50.0);
+        for (double fit : osnrPolynomialFits) {
+            contrib += pwrFact * fit;
+            pwrFact *= pwrIn;
+            // Using a for loop with multiplication instead of Math.pow optimizes the computation.
         }
-
+        // Double is not strictly spoken a Mathematics commutative group because
+        // computers design limits their bits representation size.
+        // As a result, the order of arithmetic operation matters.
+        // In a sum, smallest numbers should be introduced first for a maximum of
+        // precision. In other words, the sum
+        //    10 * Math.log10(spacing / 50.0)
+        //    + osnrPolynomialFits.get(0)
+        //    + osnrPolynomialFits.get(1) * pwrIn
+        //    + osnrPolynomialFits.get(2) * Math.pow(pwrIn, 2)
+        //    + osnrPolynomialFits.get(3) * Math.pow(pwrIn, 3)
+        // is not equal to its reverse form
+        //    osnrPolynomialFits.get(3) * Math.pow(pwrIn, 3)
+        //    + osnrPolynomialFits.get(2) * Math.pow(pwrIn, 2)
+        //    + osnrPolynomialFits.get(1) * pwrIn
+        //    + osnrPolynomialFits.get(0)
+        //    + 10 * Math.log10(spacing / 50.0)
+        // and the more precise first form should be preferred here.
+        onsrLin += Math.pow(10, -contrib / 10);
+        Map<String, Double> impairments = new HashMap<>();
+        impairments.put("CD", cd);
+        impairments.put("DGD2", dgd2);
+        impairments.put("PDL2", pdl2);
+        impairments.put("ONSRLIN", onsrLin);
+        LOG.info("Accumulated CD is {} ps, DGD2 is {} ps and PDL2 is {} dB", cd, Math.sqrt(dgd2), Math.sqrt(pdl2));
+        LOG.info("Resulting OSNR is {} dB", 10 * Math.log10(1 / onsrLin));
         return impairments;
     }
 
@@ -726,27 +694,19 @@ public class CatalogUtils {
         double constanteC0 = 0 ;
         if (spacing > 162.5) {
             constanteC0 = CatalogConstant.NLCONSTANTC0GT1625;
-        }
-        else if (spacing > 112.5) {
+        } else if (spacing > 112.5) {
             constanteC0 = CatalogConstant.NLCONSTANTC0UPTO1625;
-        }
-        else if (spacing > 100.0) {
+        } else if (spacing > 100.0) {
             constanteC0 = CatalogConstant.NLCONSTANTC0UPTO1125;
-        }
-        else if (spacing > 87.5) {
+        } else if (spacing > 87.5) {
             constanteC0 = CatalogConstant.NLCONSTANTC0UPTO1000;
-        }
-        else {
+        } else {
             constanteC0 = CatalogConstant.NLCONSTANTC0UPTO875;
         }
-
-        double nonLinearOnsrContributionLin = Math.pow(10.0, -(launchedPowerdB * CatalogConstant.NLCONSTANTC1
-            + constanteC0
-            + CatalogConstant.NLCONSTANTCE * Math.exp(CatalogConstant.NLCONSTANTEX * spanLength)) / 10);
-        LOG.info(" OSNR Non Linear contribution is {} dB", launchedPowerdB * CatalogConstant.NLCONSTANTC1
-            + constanteC0
-            + CatalogConstant.NLCONSTANTCE * Math.exp(CatalogConstant.NLCONSTANTEX * spanLength));
-        return nonLinearOnsrContributionLin;
+        double nonLinearOnsrContributionLinDb = launchedPowerdB * CatalogConstant.NLCONSTANTC1
+            + constanteC0 + CatalogConstant.NLCONSTANTCE * Math.exp(CatalogConstant.NLCONSTANTEX * spanLength);
+        LOG.info(" OSNR Non Linear contribution is {} dB", nonLinearOnsrContributionLinDb);
+        return Math.pow(10.0, -nonLinearOnsrContributionLinDb / 10);
     }
 
 }