Autonomous impairment aware path computation 63/103663/21 master
authororenais <olivier.renais@orange.com>
Tue, 31 Jan 2023 16:00:04 +0000 (17:00 +0100)
committerorenais <olivier.renais@orange.com>
Fri, 3 Feb 2023 16:45:14 +0000 (17:45 +0100)
- in PostAlgoValidator, adapt checkOSNR to scan the path in both AtoZ
and ZtoA directions, and to calculate impairments using catalog
primitives
- add to CatalogUtils some complementary primitives that were missing
getPceRoadmAmpOutputPower
- add to PceOpticalNode and PceLink missing methods
- refactor GraphTest for integration test associated with path
computation and add portMapping2.json and or-base-topology.json with
adpted OMS parameters

JIRA: TRNSPRTPCE-517 TRNSPRTPCE-605
Change-Id: I00973dcd0898d786c421c46f031d9b2b915514e8
Signed-off-by: orenais <olivier.renais@orange.com>
20 files changed:
common/src/main/java/org/opendaylight/transportpce/common/InstanceIdentifiers.java
common/src/main/java/org/opendaylight/transportpce/common/StringConstants.java
common/src/main/java/org/opendaylight/transportpce/common/catalog/CatalogUtils.java
common/src/test/java/org/opendaylight/transportpce/common/catalog/CatalogUtilsTest.java
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/FrequenciesServiceImpl.java
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmTopology.java
networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/service/FrequenciesServiceTest.java
pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java
pce/src/main/java/org/opendaylight/transportpce/pce/graph/PceGraph.java
pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java
pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceLink.java
pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceNode.java
pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceOpticalNode.java
pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceOtnNode.java
pce/src/test/java/org/opendaylight/transportpce/pce/graph/PceGraphTest.java
pce/src/test/java/org/opendaylight/transportpce/pce/networkanalyzer/PceLinkTest.java
pce/src/test/java/org/opendaylight/transportpce/pce/utils/NodeUtils.java
pce/src/test/resources/apidocCatalog10_1OptSpecV5_1.json [new file with mode: 0644]
pce/src/test/resources/topologyData/or-base-topology.json [new file with mode: 0644]
pce/src/test/resources/topologyData/portMapping2.json [new file with mode: 0644]

index 2cbd0a1..587a223 100644 (file)
@@ -8,10 +8,17 @@
 
 package org.opendaylight.transportpce.common;
 
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.TerminationPoint1;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
@@ -45,4 +52,59 @@ public final class InstanceIdentifiers {
         // Instance should be not created
     }
 
+    /**
+     * Get an instance identifier related to network termination point.
+     * @param nodeId String
+     * @param tpId String
+     * @return InstanceIdentifier
+     */
+    public static InstanceIdentifier<TerminationPoint1> createNetworkTerminationPoint1IIDBuilder(String nodeId,
+                                                                                                       String tpId) {
+        return InstanceIdentifier.builder(Networks.class)
+                .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226
+                        .networks.network.Node.class,
+                    new NodeKey(new NodeId(nodeId)))
+                .augmentation(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226
+                        .Node1.class)
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226
+                        .networks.network.node.TerminationPoint.class,
+                    new TerminationPointKey(new TpId(tpId)))
+                .augmentation(TerminationPoint1.class)
+                .build();
+    }
+
+    public static InstanceIdentifier<TerminationPoint> createNetworkTerminationPointIIDBuilder(String nodeId,
+        String tpId) {
+
+        return InstanceIdentifier.builder(Networks.class)
+                .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226
+                        .networks.network.Node.class,
+                    new NodeKey(new NodeId(nodeId)))
+                .augmentation(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226
+                        .Node1.class)
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226
+                        .networks.network.node.TerminationPoint.class,
+                    new TerminationPointKey(new TpId(tpId)))
+                .build();
+    }
+
+
+    /**
+     * Get an instance identifier related to network termination point.
+     * @param nodeId String
+     * @return InstanceIdentifier
+     */
+    public static InstanceIdentifier<Node1> createNodeIIDBuilder(String nodeId) {
+        return InstanceIdentifier.builder(Networks.class)
+                .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226
+                        .networks.network.Node.class,
+                    new NodeKey(new NodeId(nodeId)))
+                .augmentation(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226
+                        .Node1.class)
+                .build();
+    }
+
 }
index d88754a..1d6c9cf 100644 (file)
@@ -8,6 +8,9 @@
 
 package org.opendaylight.transportpce.common;
 
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.Uint32;
+
 public final class StringConstants {
 
     public static final String OPENROADM_DEVICE_MODEL_NAME = "org-openroadm-device";
@@ -48,6 +51,16 @@ public final class StringConstants {
 
     public static final String SERVICE_DIRECTION_AZ = "aToz";
     public static final String SERVICE_DIRECTION_ZA = "zToa";
+    public static final String UNKNOWN_MODE = "Unknown Mode";
+
+    public static final Map<String, Uint32> SERVICE_TYPE_RATE = Map.of(
+        SERVICE_TYPE_100GE_T, ServiceRateConstant.RATE_100,
+        SERVICE_TYPE_OTU4, ServiceRateConstant.RATE_100,
+        SERVICE_TYPE_ODUC2, ServiceRateConstant.RATE_200,
+        SERVICE_TYPE_ODUC3, ServiceRateConstant.RATE_300,
+        SERVICE_TYPE_ODUC4, ServiceRateConstant.RATE_400,
+        SERVICE_TYPE_400GE, ServiceRateConstant.RATE_400);
+
 
     private StringConstants() {
         // hiding the default constructor
index f4a807f..6976970 100644 (file)
@@ -14,6 +14,7 @@ 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.catalog.CatalogConstant.CatalogNodeType;
 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;
@@ -37,6 +38,8 @@ import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.
 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.transponder.parameters.Penalties;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.transponder.parameters.PenaltiesKey;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.operational.mode.transponder.parameters.TXOOBOsnrKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.power.mask.MaskPowerVsPin;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.operational.mode.catalog.rev211210.power.mask.MaskPowerVsPinKey;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.OperationalModeCatalog;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -78,7 +81,8 @@ public class CatalogUtils {
     }
 
     /**
-     * Following method returns default OperationalModeId for devices that do not expose them.
+     * Following method returns default OperationalModeId for devices that do not
+     * expose them.
      *
      * @param catalogNodeType
      *            identifies type of nodes in the catalog
@@ -88,7 +92,7 @@ public class CatalogUtils {
      * @return a default operational mode that corresponds to initial specifications
      *
      */
-    public String getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType catalogNodeType,
+    public String getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType catalogNodeType,
             String serviceType) {
         if (CATALOGNODETYPE_OPERATIONMODEID_MAP.containsKey(catalogNodeType)) {
             return CATALOGNODETYPE_OPERATIONMODEID_MAP.get(catalogNodeType);
@@ -372,7 +376,10 @@ public class CatalogUtils {
         penalty = getRxTspPenalty(calcPmd, ImpairmentType.PMDPs, penaltiesMap);
         impairments.put("PMD Penalty", penalty);
         totalPenalty += penalty;
-        penalty = getRxTspPenalty(calcPdl, ImpairmentType.PDLDB, penaltiesMap);
+        // Calculation according to OpenROADM specification
+        // penalty = getRxTspPenalty(calcPdl, ImpairmentType.PDLDB, penaltiesMap);
+        // Calculation modified according to Julia's Tool
+        penalty = calcPdl / 2;
         impairments.put("PDL penalty", penalty);
         totalPenalty += penalty;
         // TODO for Future work since at that time we have no way to calculate the following
@@ -497,7 +504,10 @@ public class CatalogUtils {
                     LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAddOM);
                     networkTransactionService.close();
                     maxIntroducedCd = orAddOM.getMaxIntroducedCd().doubleValue();
-                    maxIntroducedPdl = orAddOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    // As per current OpenROADM Spec
+                    //maxIntroducedPdl = orAddOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    // Applying calculation as provided in Julia's tool
+                    maxIntroducedPdl = Math.sqrt(0.2 * 0.2 + 0.4 * 0.4);
                     maxIntroducedDgd = orAddOM.getMaxIntroducedDgd().doubleValue();
                     osnrPolynomialFits = List.of(orAddOM.getIncrementalOsnr().getValue().doubleValue());
                 } catch (InterruptedException | ExecutionException e) {
@@ -531,7 +541,10 @@ public class CatalogUtils {
                     LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orDropOM);
                     networkTransactionService.close();
                     maxIntroducedCd = orDropOM.getMaxIntroducedCd().doubleValue();
-                    maxIntroducedPdl = orDropOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    // As per current OpenROADM Spec
+                    // maxIntroducedPdl = orDropOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    // Applying calculation as provided in Julia's tool
+                    maxIntroducedPdl = Math.sqrt(0.2 * 0.2 + 0.4 * 0.4);
                     maxIntroducedDgd = orDropOM.getMaxIntroducedDgd().doubleValue();
                     osnrPolynomialFits = List.of(
                         orDropOM.getOsnrPolynomialFit().getD().doubleValue(),
@@ -575,7 +588,10 @@ public class CatalogUtils {
                     var orExpressOM = omOptional.get();
                     LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orExpressOM);
                     maxIntroducedCd = orExpressOM.getMaxIntroducedCd().doubleValue();
-                    maxIntroducedPdl = orExpressOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    // As per current OpenROADM Spec
+                    // maxIntroducedPdl = orExpressOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    // Applying calculation as provided in Julia's tool
+                    maxIntroducedPdl = Math.sqrt(2 * 0.2 * 0.2 + 2 * 0.4 * 0.4);
                     maxIntroducedDgd = orExpressOM.getMaxIntroducedDgd().doubleValue();
                     osnrPolynomialFits = List.of(
                         orExpressOM.getOsnrPolynomialFit().getD().doubleValue(),
@@ -613,7 +629,10 @@ public class CatalogUtils {
                     LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAmpOM);
                     networkTransactionService.close();
                     maxIntroducedCd = orAmpOM.getMaxIntroducedCd().doubleValue();
-                    maxIntroducedPdl = orAmpOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    // As per current OpenROADM Spec
+                    // maxIntroducedPdl = orAmpOM.getMaxIntroducedPdl().getValue().doubleValue();
+                    // Applying calculation as provided in Julia's tool
+                    maxIntroducedPdl = 0.2;
                     maxIntroducedDgd = orAmpOM.getMaxIntroducedDgd().doubleValue();
                     osnrPolynomialFits = List.of(
                         orAmpOM.getOsnrPolynomialFit().getD().doubleValue(),
@@ -638,7 +657,14 @@ public class CatalogUtils {
         pdl2 += Math.pow(maxIntroducedPdl, 2.0);
         dgd2 += Math.pow(maxIntroducedDgd, 2.0);
         double pwrFact = 1;
-        double contrib = 10 * Math.log10(spacing / 50.0);
+        double contrib = 0;
+        // We correct PwrIn to the value corresponding to a 50 GHz Bandwidth, because OpenROADM spec (polynomial fit)
+        // is based on power in 50GHz Bandwidth
+        pwrIn -= 10 * Math.log10(spacing / 50.0);
+        if (catalogNodeType != CatalogNodeType.ADD) {
+            // For add, incremental OSNR is defined for Noiseless input, BW Correction (contrib) does not apply
+            contrib = 10 * Math.log10(spacing / 50.0);
+        }
         for (double fit : osnrPolynomialFits) {
             contrib += pwrFact * fit;
             pwrFact *= pwrIn;
@@ -667,11 +693,130 @@ public class CatalogUtils {
         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("Accumulated CD is {} ps, DGD is {} ps and PDL is {} dB", cd, Math.sqrt(dgd2), Math.sqrt(pdl2));
         LOG.info("Resulting OSNR is {} dB", 10 * Math.log10(1 / onsrLin));
         return impairments;
     }
 
+    /**
+     * This method calculates power that shall be applied at the output of ROADMs and
+     * Amplifiers. It retrieves the mask-power-vs-Pin and calculates target output
+     * power from the span loss
+     *
+     * @param catalogNodeType
+     *            crossed node path type (ADD/EXPRESS/AMP)
+     * @param operationalModeId
+     *            operational-mode-Id of the Node (OpenROADM only)
+     * @param spanLoss
+     *            spanLoss at the output of the ROADM
+     * @param powerCorrection
+     *            correction to be applied to the calculated power according to fiber type
+     * @param spacing
+     *            Interchannel spacing used for correction to calculate output power
+     * @return outputPower
+     *         Corrected output power calculated according to channel spacing
+     * @throws RuntimeException
+     *             if operationalModeId is not described in the catalog
+     */
+    public double getPceRoadmAmpOutputPower(CatalogConstant.CatalogNodeType catalogNodeType,
+            String operationalModeId, double spanLoss, double spacing, double powerCorrection) {
+        double pout = 99999.0;
+        switch (catalogNodeType) {
+            case ADD:
+                var omCatalogIid = InstanceIdentifier
+                    .builder(OperationalModeCatalog.class)
+                    .child(OpenroadmOperationalModes.class)
+                    .child(Roadms.class)
+                    .child(Add.class)
+                    .child(AddOpenroadmOperationalMode.class, new AddOpenroadmOperationalModeKey(operationalModeId))
+                    .build();
+                try {
+                    var omOptional =
+                        networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get();
+                    if (omOptional.isEmpty()) {
+                        LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
+                        return pout;
+                    }
+                    var orAddOM = omOptional.get();
+                    LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orAddOM);
+                    networkTransactionService.close();
+                    var mask = orAddOM.getMaskPowerVsPin();
+                    for (Map.Entry<MaskPowerVsPinKey, MaskPowerVsPin> pw : mask.entrySet()) {
+                        if (spanLoss >= pw.getKey().getLowerBoundary().doubleValue()
+                            && spanLoss <= pw.getKey().getUpperBoundary().doubleValue()) {
+                            pout = pw.getValue().getC().doubleValue() * spanLoss + pw.getValue().getD().doubleValue()
+                                + powerCorrection + 10 * Math.log10(spacing / 50.0);
+                            LOG.info("Calculated target Output power is {} dB in {} Bandwidth", pout, spacing);
+                            return pout;
+                        }
+                    }
+                    LOG.info("Did not succeed in calculating target Output power, SpanLoss {} dB is out of range",
+                        spanLoss);
+                } 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);
+                } finally {
+                    networkTransactionService.close();
+                }
+                break;
+
+            case EXPRESS:
+                var omCatalogIid2 = InstanceIdentifier
+                    .builder(OperationalModeCatalog.class)
+                    .child(OpenroadmOperationalModes.class)
+                    .child(Roadms.class)
+                    .child(Express.class)
+                    .child(
+                        org.opendaylight.yang.gen.v1.http
+                            .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))
+                    .build();
+                try {
+                    var omOptional = networkTransactionService
+                        .read(LogicalDatastoreType.CONFIGURATION, omCatalogIid2)
+                        .get();
+                    if (omOptional.isEmpty()) {
+                        LOG.error(OPMODE_MISMATCH_MSG, operationalModeId);
+                        return pout;
+                    }
+                    var orExpressOM = omOptional.get();
+                    LOG.debug("readMdSal: Operational Mode Catalog: omOptional.isPresent = true {}", orExpressOM);
+                    var mask = orExpressOM.getMaskPowerVsPin();
+                    for (Map.Entry<MaskPowerVsPinKey, MaskPowerVsPin> pw : mask.entrySet()) {
+                        if (spanLoss >= pw.getKey().getLowerBoundary().doubleValue()
+                                && spanLoss <= pw.getKey().getUpperBoundary().doubleValue()) {
+                            pout = pw.getValue().getC().doubleValue() * spanLoss + pw.getValue().getD().doubleValue()
+                                + powerCorrection + 10 * Math.log10(spacing / 50.0);
+                            LOG.info("Calculated target Output power is {} dB in {} Bandwidth", pout, spacing);
+                            return pout;
+                        }
+                    }
+                    LOG.info("Did not succeed in calculating target Output power, SpanLoss {} dB is out of range",
+                        spanLoss);
+                } catch (InterruptedException | ExecutionException e) {
+                    LOG.error("readMdSal: Error reading Operational Mode Catalog {} , Mode does not exist",
+                        omCatalogIid2);
+                    throw new RuntimeException(
+                        "readMdSal: Error reading from operational store, Operational Mode Catalog : "
+                            + omCatalogIid2 + " :" + e);
+                } finally {
+                    networkTransactionService.close();
+                }
+                break;
+
+            default:
+                LOG.error("Unsupported catalogNodeType {}", catalogNodeType);
+        }
+        return pout;
+    }
+
     /**
      * Non linear contribution computation.
      * Public method calculating non linear contribution among the path from
@@ -709,4 +854,28 @@ public class CatalogUtils {
         return Math.pow(10.0, -nonLinearOnsrContributionLinDb / 10);
     }
 
+    public boolean isCatalogFilled() {
+        var omCatalogIid = InstanceIdentifier
+            .builder(OperationalModeCatalog.class)
+            .child(OpenroadmOperationalModes.class)
+            .child(Roadms.class)
+            .child(Add.class)
+            .child(AddOpenroadmOperationalMode.class, new AddOpenroadmOperationalModeKey(CatalogConstant.MWWRCORE))
+            .build();
+        try {
+            if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, omCatalogIid).get().isEmpty()) {
+                LOG.error("Operational Mode catalog is not filled");
+                return false;
+            }
+            networkTransactionService.close();
+            return true;
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("readMdSal: Error reading Operational Mode Catalog, catalog not filled");
+            throw new RuntimeException(
+                "readMdSal: Error reading from operational store, Operational Mode Catalog not filled" + e);
+        } finally {
+            networkTransactionService.close();
+        }
+    }
+
 }
index f6d7104..2df102b 100644 (file)
@@ -76,43 +76,43 @@ public class CatalogUtilsTest extends AbstractTest {
         CatalogUtils catalogUtils = new CatalogUtils(netTransServ);
         assertEquals("Checking retrieval of Operational Mode from Node Type ADD",
             CatalogConstant.MWWRCORE,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.ADD,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.ADD,
                 StringConstants.SERVICE_TYPE_100GE_T));
         assertEquals("Checking retrieval of Operational Mode from Node Type DROP",
             CatalogConstant.MWWRCORE,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.DROP,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.DROP,
                 StringConstants.SERVICE_TYPE_100GE_T));
         assertEquals("Checking retrieval of Operational Mode from Node Type EXPRESS",
             CatalogConstant.MWMWCORE,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.EXPRESS,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.EXPRESS,
                 StringConstants.SERVICE_TYPE_100GE_T));
         assertEquals("Checking retrieval of Operational Mode from Node Type AMP",
             CatalogConstant.MWISTANDARD,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.AMP,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.AMP,
                 StringConstants.SERVICE_TYPE_100GE_T));
         assertEquals("Checking retrieval of Operational Mode from Node Type and service Type 100GE",
             CatalogConstant.ORW100GSC,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
                 StringConstants.SERVICE_TYPE_100GE_T));
         assertEquals("Checking retrieval of Operational Mode from Node Type and service Type OTU4",
             CatalogConstant.ORW100GSC,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
                 StringConstants.SERVICE_TYPE_OTU4));
         assertEquals("Checking retrieval of Operational Mode from Node Type and service Type OTUC2",
             CatalogConstant.ORW200GOFEC316GBD,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
                 StringConstants.SERVICE_TYPE_OTUC2));
         assertEquals("Checking retrieval of Operational Mode from Node Type and service Type OTUC3",
             CatalogConstant.ORW300GOFEC631GBD,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
                 StringConstants.SERVICE_TYPE_OTUC3));
         assertEquals("Checking retrieval of Operational Mode from Node Type and service Type 400GE",
             CatalogConstant.ORW400GOFEC631GBD,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
                 StringConstants.SERVICE_TYPE_400GE));
         assertEquals("Checking retrieval of Operational Mode from Node Type and service Type OTUC4",
             CatalogConstant.ORW400GOFEC631GBD,
-            catalogUtils.getPceTxTspOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
+            catalogUtils.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
                 StringConstants.SERVICE_TYPE_OTUC4));
         assertEquals("Checking retrieval of channel spacing from Operational Mode 100G SC FEC",
             50.0,
@@ -164,9 +164,9 @@ public class CatalogUtilsTest extends AbstractTest {
         assertEquals("Checking 100GSCFEC RX margin OOR due to PMD",
             -9996.9, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GSC, 0.0, 30.1, 0.0, 20.0), 0.5);
         assertEquals("Checking 100GSCFEC RX margin OOR due to PDL",
-            -9996.9, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GSC, 0.0, 0.0, 6.1, 20.0), 0.5);
+            0.0, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GSC, 0.0, 0.0, 6.0, 20.0), 0.5);
         assertEquals("Checking 100GSCFEC RX margin in Range at max tolerated penalty",
-            3.0, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GSC, 17999.0, 29.9, 5.9, 20.0), 0.05);
+            0.0, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GSC, 17999.0, 29.9, 6.0, 20.0), 0.05);
         assertEquals("Checking 400G OFEC 63.1 Gbauds RX margin OOR due to CD",
             -9996.9, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 12001.0, 0.0, 0.0, 27.0),
             0.5);
@@ -174,67 +174,67 @@ public class CatalogUtilsTest extends AbstractTest {
             -9996.9, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 0.0, 20.1, 0.0, 27.0),
             0.5);
         assertEquals("Checking 400G OFEC 63.1 Gbauds RX margin OOR due to PDL",
-            -9996.9, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 0.0, 0.0, 4.1, 27.0),
+            0.0, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 0.0, 0.0, 6.0, 27.0),
             0.5);
         assertEquals("Checking 400G OFEC 63.1 Gbauds RX margin in Range at max tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 11999.0, 19.9, 3.9, 28.0),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 11999.0, 19.9, 5.0, 28.0),
             0.05);
         assertEquals("Checking 400G OFEC 63.1 Gbauds RX margin in Range at intermediate tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 3999.0, 9.9, 1.9, 25.5),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 3999.0, 9.9, 2.0, 25.5),
             0.05);
         assertEquals("Checking 400G OFEC 63.1 Gbauds RX margin in Range at min tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 3999.0, 9.9, 0.9, 25.0),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW400GOFEC631GBD, 3999.0, 9.9, 1.0, 25.0),
             0.05);
         assertEquals("Checking 300G OFEC 63.1 Gbauds RX margin in Range at max tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW300GOFEC631GBD, 17999.0, 24.9, 3.9, 25.0),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW300GOFEC631GBD, 17999.0, 24.9, 5.0, 25.0),
             0.05);
         assertEquals("Checking 300G OFEC 63.1 Gbauds RX margin in Range at min tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW300GOFEC631GBD, 3999.0, 9.9, 0.9, 22.0),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW300GOFEC631GBD, 3999.0, 9.9, 1.0, 22.0),
             0.05);
         assertEquals("Checking 200G OFEC 63.1 Gbauds RX margin in Range at max tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW200GOFEC631GBD, 23999.0, 24.9, 3.9, 21.0),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW200GOFEC631GBD, 23999.0, 24.9, 5.0, 21.0),
             0.05);
         assertEquals("Checking 200G OFEC 63.1 Gbauds RX margin in Range at min tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW200GOFEC631GBD, 3999.0, 9.9, 0.9, 18.0),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW200GOFEC631GBD, 3999.0, 9.9, 1.0, 18.0),
             0.05);
         assertEquals("Checking 200G OFEC 31.6 Gbauds RX margin in Range at max tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW200GOFEC316GBD, 23999.0, 29.9, 3.9, 24.5),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW200GOFEC316GBD, 23999.0, 29.9, 5.0, 24.5),
             0.05);
         assertEquals("Checking 200G OFEC 31.6 Gbauds RX margin in Range at min tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW200GOFEC316GBD, 3999.0, 9.9, 0.9, 21.5),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW200GOFEC316GBD, 3999.0, 9.9, 1.0, 21.5),
             0.05);
         assertEquals("Checking 100G OFEC 31.6 Gbauds RX margin in Range at max tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GOFEC316GBD, 47999.0, 29.9, 3.9, 16.0),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GOFEC316GBD, 47999.0, 29.9, 5.0, 16.0),
             0.05);
         assertEquals("Checking 100G OFEC 31.6 Gbauds RX margin in Range at min tolerated penalty",
-            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GOFEC316GBD, 3999.0, 9.9, 0.9, 13.0),
+            0.5, catalogUtils.getPceRxTspParameters(CatalogConstant.ORW100GOFEC316GBD, 3999.0, 9.9, 1.0, 13.0),
             0.05);
         assertEquals("Checking Margin negative for non valid OM",
             -9999.9, catalogUtils.getPceRxTspParameters("SPE-non-existing-mode", 0.0, 0.0, 0.0, 30.0), 0.05);
         outputImpairments.put("CD", 1025.0);
         outputImpairments.put("DGD2", 18.0);
-        outputImpairments.put("PDL2", 6.25);
+        outputImpairments.put("PDL2", 4.4);
         outputImpairments.put("ONSRLIN", 0.0016307685044580757);
         // check how to add Delta on an object<String, Double>
         assertEquals("Checking ROADM Express path contribution to impairments ",
             outputImpairments, catalogUtils.getPceRoadmAmpParameters(CatalogConstant.CatalogNodeType.EXPRESS,
             CatalogConstant.MWMWCORE,-15.0, 1000.0, 9.0, 4.0, 0.001000, 50.0));
-        outputImpairments.put("ONSRLIN", 0.0013604391454046147);
+        outputImpairments.put("ONSRLIN", 0.0014729700859390747);
         assertEquals("Checking ROADM Express path contribution to impairments with 87.5 GHz spacing ",
             outputImpairments, catalogUtils.getPceRoadmAmpParameters(CatalogConstant.CatalogNodeType.EXPRESS,
             CatalogConstant.MWMWCORE,-15.0, 1000.0, 9.0, 4.0, 0.001000, 87.5));
         outputImpairments.put("ONSRLIN", 0.0015011872336272727);
         assertEquals("Checking ROADM Add path contribution to impairments ",
             outputImpairments, catalogUtils.getPceRoadmAmpParameters(CatalogConstant.CatalogNodeType.ADD,
-            CatalogConstant.MWWRCORE, -15.0, 1000.0, 9.0, 4.0, 0.001, 50.0));
+            CatalogConstant.MWWRCORE, -15.0, 1000.0, 9.0, 4.2, 0.001, 50.0));
         outputImpairments.put("ONSRLIN", 0.0016307685044580757);
         assertEquals("Checking ROADM Drop path contribution to impairments ",
             outputImpairments, catalogUtils.getPceRoadmAmpParameters(CatalogConstant.CatalogNodeType.DROP,
-            CatalogConstant.MWWRCORE, -15.0, 1000.0, 9.0, 4.0, 0.001, 50.0));
+            CatalogConstant.MWWRCORE, -15.0, 1000.0, 9.0, 4.2, 0.001, 50.0));
         outputImpairments.put("ONSRLIN", 0.0015010372326658581);
         assertEquals("Checking Amp path contribution to impairments ",
             outputImpairments, catalogUtils.getPceRoadmAmpParameters(CatalogConstant.CatalogNodeType.AMP,
-            CatalogConstant.MWISTANDARD, -15.0, 1025.0, 9.0, 5.76, 0.001, 50.0));
+            CatalogConstant.MWISTANDARD, -15.0, 1025.0, 9.0, 4.36, 0.001, 50.0));
         assertEquals("Checking empty map returned in case wrong Operational mode provided  ",
             true, catalogUtils.getPceRoadmAmpParameters(CatalogConstant.CatalogNodeType.AMP,
                 "ThisIsNotAValidMode", -15.0,1000.0, 0.0, 0.0, 0.001, 50.0).isEmpty());
index 26e4100..95cfbf6 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.ReadTransaction;
 import org.opendaylight.mdsal.binding.api.WriteTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.InstanceIdentifiers;
 import org.opendaylight.transportpce.common.NetworkUtils;
 import org.opendaylight.transportpce.common.NodeIdPair;
 import org.opendaylight.transportpce.common.Timeouts;
@@ -214,8 +215,8 @@ public class FrequenciesServiceImpl implements FrequenciesService {
      * @return network termination point, null otherwise
      */
     private TerminationPoint1 getNetworkTerminationPointFromDatastore(String nodeId, String tpId) {
-        InstanceIdentifier<TerminationPoint1> tpIID = OpenRoadmTopology
-                .createNetworkTerminationPointIIDBuilder(nodeId, tpId).build();
+        InstanceIdentifier<TerminationPoint1> tpIID = InstanceIdentifiers
+                .createNetworkTerminationPoint1IIDBuilder(nodeId, tpId);
         try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
             Optional<TerminationPoint1> optionalTerminationPoint = readTx
                     .read(LogicalDatastoreType.CONFIGURATION, tpIID)
@@ -349,9 +350,9 @@ public class FrequenciesServiceImpl implements FrequenciesService {
                     LOG.warn("Termination point type {} not managed", commonNetworkTerminationPoint.getTpType());
                     return;
             }
-            updateFrequenciesTransaction.put(LogicalDatastoreType.CONFIGURATION, OpenRoadmTopology
-                    .createNetworkTerminationPointIIDBuilder(idPair.getNodeID(),
-                            idPair.getTpID()).build(), networkTerminationPointBuilder.build());
+            updateFrequenciesTransaction.put(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers
+                    .createNetworkTerminationPoint1IIDBuilder(idPair.getNodeID(),
+                            idPair.getTpID()), networkTerminationPointBuilder.build());
         }
         try {
             updateFrequenciesTransaction.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
index bcdab98..c625fc6 100644 (file)
@@ -33,7 +33,6 @@ import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191
 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.Node1;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.Node1Builder;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.TerminationPoint1;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.DegreeAttributes;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.DegreeAttributesBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.SrgAttributes;
@@ -564,27 +563,6 @@ public final class OpenRoadmTopology {
                         .TerminationPoint1.class);
     }
 
-    /**
-     * Get a builder for instance identifier related to network termination point.
-     * @param nodeId String
-     * @param tpId String
-     * @return InstanceIdentifierBuilder
-     */
-    public static InstanceIdentifierBuilder<TerminationPoint1> createNetworkTerminationPointIIDBuilder(String nodeId,
-                                                                                                       String tpId) {
-        return InstanceIdentifier.builder(Networks.class)
-                .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
-                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226
-                        .networks.network.Node.class,
-                    new NodeKey(new NodeId(nodeId)))
-                .augmentation(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226
-                        .Node1.class)
-                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226
-                        .networks.network.node.TerminationPoint.class,
-                    new TerminationPointKey(new TpId(tpId)))
-                .augmentation(TerminationPoint1.class);
-    }
-
     /**
      * Get an instance identifier related to network node.
      * @param nodeId String
index 20be031..cf3eb84 100644 (file)
@@ -114,8 +114,8 @@ public class FrequenciesServiceTest extends AbstractTest {
     }
 
     private TerminationPoint1 getNetworkTerminationPointFromDatastore(String nodeId, String tpId) {
-        InstanceIdentifier<TerminationPoint1> tpIID = OpenRoadmTopology
-                .createNetworkTerminationPointIIDBuilder(nodeId, tpId).build();
+        InstanceIdentifier<TerminationPoint1> tpIID = InstanceIdentifiers
+                .createNetworkTerminationPoint1IIDBuilder(nodeId, tpId);
         try (ReadTransaction readTx = getDataBroker().newReadOnlyTransaction()) {
             Optional<TerminationPoint1> optionalTerminationPoint = readTx
                     .read(LogicalDatastoreType.CONFIGURATION, tpIID)
index 452b711..ba757dc 100644 (file)
@@ -121,7 +121,8 @@ public class PceSendingPceRPCs {
         }
         LOG.info("PceGraph ...");
         PceGraph graph = new PceGraph(nwAnalizer.getaendPceNode(), nwAnalizer.getzendPceNode(),
-                nwAnalizer.getAllPceNodes(), hardConstraints, softConstraints, rc, serviceType);
+                nwAnalizer.getAllPceNodes(), nwAnalizer.getAllPceLinks(), hardConstraints, softConstraints,
+                rc, serviceType, networkTransaction);
         graph.calcPath();
         rc = graph.getReturnStructure();
         if (!rc.getStatus()) {
index 583ac45..0a2d75f 100644 (file)
@@ -23,6 +23,7 @@ import org.jgrapht.alg.shortestpath.PathValidator;
 import org.jgrapht.graph.DefaultDirectedWeightedGraph;
 import org.opendaylight.transportpce.common.ResponseCodes;
 import org.opendaylight.transportpce.common.StringConstants;
+import org.opendaylight.transportpce.common.network.NetworkTransactionService;
 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceLink;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceNode;
@@ -30,6 +31,7 @@ import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult.LocalCause;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,17 +41,18 @@ public class PceGraph {
 
     ////////////////////////// for Graph ///////////////////////////
     // how many paths to bring
-    private int kpathsToBring = 10;
+    private int kpathsToBring = 15;
 
     // max #hops
-    private int mhopsPerPath = 50;
+    private int mhopsPerPath = 100;
 
     // input
     private Map<NodeId, PceNode> allPceNodes = new HashMap<>();
+    private Map<LinkId, PceLink> allPceLinks = new HashMap<>();
     private PceNode apceNode = null;
     private PceNode zpceNode = null;
     private String serviceType = "";
-
+    private Double margin = null;
     PceConstraints pceHardConstraints;
     PceConstraints pceSoftConstraints;
 
@@ -62,17 +65,21 @@ public class PceGraph {
 
     private List<PceLink> pathAtoZ = new ArrayList<>();
 
+    private final NetworkTransactionService networkTransactionService;
+
     public PceGraph(PceNode aendNode, PceNode zendNode, Map<NodeId, PceNode> allPceNodes,
-            PceConstraints pceHardConstraints, PceConstraints pceSoftConstraints, PceResult pceResult,
-            String serviceType) {
+            Map<LinkId, PceLink> allPceLinks, PceConstraints pceHardConstraints, PceConstraints pceSoftConstraints,
+            PceResult pceResult, String serviceType, NetworkTransactionService networkTransactionService) {
         super();
         this.apceNode = aendNode;
         this.zpceNode = zendNode;
         this.allPceNodes = allPceNodes;
+        this.allPceLinks = allPceLinks;
         this.pceResult = pceResult;
         this.pceHardConstraints = pceHardConstraints;
         this.pceSoftConstraints = pceSoftConstraints;
         this.serviceType = serviceType;
+        this.networkTransactionService = networkTransactionService;
 
         LOG.info("In GraphCalculator: A and Z = {} / {} ", aendNode, zendNode);
         LOG.debug("In GraphCalculator: allPceNodes size {}, nodes {} ", allPceNodes.size(), allPceNodes);
@@ -96,8 +103,9 @@ public class PceGraph {
         for (Entry<Integer, GraphPath<String, PceGraphEdge>> entry : allWPaths.entrySet()) {
             GraphPath<String, PceGraphEdge> path = entry.getValue();
             LOG.info("validating path n° {} - {}", entry.getKey(), path.getVertexList());
-            PostAlgoPathValidator papv = new PostAlgoPathValidator();
-            pceResult = papv.checkPath(path, allPceNodes, pceResult, pceHardConstraints, serviceType);
+            PostAlgoPathValidator papv = new PostAlgoPathValidator(networkTransactionService);
+            pceResult = papv.checkPath(path, allPceNodes, allPceLinks, pceResult, pceHardConstraints, serviceType);
+            this.margin = papv.getTpceCalculatedMargin();
             if (ResponseCodes.RESPONSE_OK.equals(pceResult.getResponseCode())) {
                 LOG.info("Path is validated");
             } else {
@@ -282,6 +290,10 @@ public class PceGraph {
         return pceResult;
     }
 
+    public Double getmargin() {
+        return margin;
+    }
+
     public void setConstrains(PceConstraints pceHardConstraintsInput, PceConstraints pceSoftConstraintsInput) {
         this.pceHardConstraints = pceHardConstraintsInput;
         this.pceSoftConstraints = pceSoftConstraintsInput;
index 7e4acd6..c283207 100644 (file)
@@ -17,21 +17,34 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
 import java.util.stream.Collectors;
 import org.jgrapht.GraphPath;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.InstanceIdentifiers;
 import org.opendaylight.transportpce.common.ResponseCodes;
 import org.opendaylight.transportpce.common.StringConstants;
+import org.opendaylight.transportpce.common.catalog.CatalogConstant;
+import org.opendaylight.transportpce.common.catalog.CatalogConstant.CatalogNodeType;
+import org.opendaylight.transportpce.common.catalog.CatalogUtils;
 import org.opendaylight.transportpce.common.fixedflex.GridConstant;
 import org.opendaylight.transportpce.common.fixedflex.GridUtils;
+import org.opendaylight.transportpce.common.network.NetworkTransactionService;
 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
 import org.opendaylight.transportpce.pce.constraints.PceConstraints.ResourcePair;
+import org.opendaylight.transportpce.pce.networkanalyzer.PceLink;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceNode;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.SpectrumAssignment;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.SpectrumAssignmentBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.TerminationPoint1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.termination.point.XpdrNetworkAttributes;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmLinkType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmNodeType;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev210924.OpucnTribSlotDef;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.Uint16;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,19 +53,24 @@ public class PostAlgoPathValidator {
     /* Logging. */
     private static final Logger LOG = LoggerFactory.getLogger(PostAlgoPathValidator.class);
 
-    private static final double MIN_OSNR_W100G = 17;
-    private static final double TRX_OSNR = 33;
-    private static final double ADD_OSNR = 30;
     public static final Long CONST_OSNR = 1L;
     public static final double SYS_MARGIN = 0;
+    private Double tpceCalculatedMargin = 0.0;
+    private final NetworkTransactionService networkTransactionService;
+
+    public PostAlgoPathValidator(NetworkTransactionService networkTransactionService) {
+        this.networkTransactionService = networkTransactionService;
+    }
 
     @SuppressWarnings("fallthrough")
     @SuppressFBWarnings(
         value = "SF_SWITCH_FALLTHROUGH",
         justification = "intentional fallthrough")
-    public PceResult checkPath(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
-        PceResult pceResult, PceConstraints pceHardConstraints, String serviceType) {
 
+    public PceResult checkPath(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
+            Map<LinkId, PceLink> allPceLinks, PceResult pceResult, PceConstraints pceHardConstraints,
+            String serviceType) {
+        LOG.info("path = {}", path);
         // check if the path is empty
         if (path.getEdgeList().isEmpty()) {
             pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
@@ -94,10 +112,26 @@ public class PostAlgoPathValidator {
                 LOG.debug("In PostAlgoPathValidator: spectrum assignment found {} {}", spectrumAssignment, path);
 
                 // Check the OSNR
-                if (!checkOSNR(path)) {
-                    pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
-                    pceResult.setLocalCause(PceResult.LocalCause.OUT_OF_SPEC_OSNR);
-                    return pceResult;
+                CatalogUtils cu = new CatalogUtils(networkTransactionService);
+                if (cu.isCatalogFilled()) {
+                    double margin1 = checkOSNR(path, allPceNodes, allPceLinks, serviceType,
+                            StringConstants.SERVICE_DIRECTION_AZ, cu);
+                    double margin2 = checkOSNR(path, allPceNodes, allPceLinks, serviceType,
+                            StringConstants.SERVICE_DIRECTION_ZA, cu);
+                    if (margin1 < 0 || margin2 < 0 || margin1 == Double.NEGATIVE_INFINITY
+                            || margin2 == Double.NEGATIVE_INFINITY) {
+                        pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
+                        pceResult.setLocalCause(PceResult.LocalCause.OUT_OF_SPEC_OSNR);
+                        return pceResult;
+                    }
+                    this.tpceCalculatedMargin = Math.min(margin1, margin2);
+                    LOG.info(
+                        "In PostAlgoPathValidator: Minimum margin estimated by tpce on AtoZ and ZtoA path is of  {} dB",
+                        this.tpceCalculatedMargin);
+                } else {
+                    this.tpceCalculatedMargin = 0.0;
+                    LOG.info("In PostAlgoPathValidator: Operational mode Catalog not filled, delegate OSNR calculation"
+                        + " to GNPy and margin set to 0");
                 }
 
                 // Check if MaxLatency is defined in the hard constraints
@@ -363,41 +397,364 @@ public class PostAlgoPathValidator {
         return minmaxTpTsList;
     }
 
-    // Check the path OSNR
-    private boolean checkOSNR(GraphPath<String, PceGraphEdge> path) {
-        double linkOsnrDb;
-        double osnrDb = 0;
-        LOG.info("- In checkOSNR: OSNR of the transmitter = {} dB", TRX_OSNR);
-        LOG.info("- In checkOSNR: add-path incremental OSNR = {} dB", ADD_OSNR);
-        double inverseLocalOsnr = getInverseOsnrLinkLu(TRX_OSNR) + getInverseOsnrLinkLu(ADD_OSNR);
-        for (PceGraphEdge edge : path.getEdgeList()) {
-            if (edge.link().getlinkType() == OpenroadmLinkType.ROADMTOROADM) {
-                // link OSNR in dB
-                linkOsnrDb = edge.link().getosnr();
-                LOG.info("- In checkOSNR: OSNR of {} = {} dB", edge.link().getLinkId().getValue(), linkOsnrDb);
-                // 1 over the local OSNR, in linear units
-                inverseLocalOsnr += getInverseOsnrLinkLu(linkOsnrDb);
+    /**
+     * Calculates the OSNR of a path, according to the direction (AtoZ/ZtoA), using the operational-modes Catalog.
+     *
+     * @param path                      the AtoZ path provided by the PCE.
+     * @param allPceNode                The map of chosen/relevant PceNodes build from topology pruning.
+     * @param allPceLinks               The map of PceLinks build corresponding to the whole topology.
+     * @param serviceType               The service Type used to extrapolate Operational mode when it is not provided.
+     * @param direction                 The direction used to scan provided path in a direct or reverse way.
+     * @param cu                        CatalogUtils instance.
+     * @return the calculated margin according to the Transponder performances and path impairments.
+     */
+    @SuppressWarnings("deprecation")
+    @edu.umd.cs.findbugs.annotations.SuppressWarnings("DLS_DEAD_LOCAL_STORE")
+    private double checkOSNR(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
+        Map<LinkId, PceLink> allPceLinks, String serviceType, String direction, CatalogUtils cu) {
+        double spacing = 50.0;
+        double calcPdl2 = 0;
+        double calcOsnrdB = 0;
+        double calcCd = 0;
+        double calcPmd2 = 0;
+        double calcOnsrLin = 0.0001;
+        double margin = 0;
+        double pwrIn = -60.0;
+        double pwrOut = -60.0;
+        int pathElement = 0;
+        int increment = 1;
+        int offsetLink = 0;
+        boolean transponderPresent = false;
+        if ((StringConstants.SERVICE_DIRECTION_ZA).equals(direction)) {
+            increment = - 1;
+            offsetLink = -1;
+        }
+        CatalogNodeType cnt;
+        List<String> vertices = path.getVertexList();
+        List<PceGraphEdge> edges = path.getEdgeList();
+        String opMode = "";
+        // LOOP that scans the different Nodes/Links of the path and calculates
+        // associated degradations
+        // using CatalogUtils primitives to retrieve physical parameters and make a
+        // first level calculation
+        Map<String, Double> impairments = new HashMap<>();
+        for (int n = 0; n < vertices.size(); n++) {
+            InstanceIdentifier<TerminationPoint1> nwTpIid;
+            PceNode nextNode = null;
+            if ((StringConstants.SERVICE_DIRECTION_AZ).equals(direction)) {
+                pathElement = n ;
+            } else {
+                pathElement = vertices.size() - n - 1;
+            }
+            PceNode currentNode = allPceNodes.get(new NodeId(vertices.get(pathElement)));
+            if (((pathElement != vertices.size() - 1) && (StringConstants.SERVICE_DIRECTION_AZ).equals(direction))
+                    || ((pathElement != 0) && (StringConstants.SERVICE_DIRECTION_ZA).equals(direction))) {
+                nextNode = allPceNodes.get(new NodeId(vertices.get(pathElement + increment)));
+            }
+            LOG.debug("loop of check OSNR, n = {} Path Element = {}", n, pathElement);
+            switch (currentNode.getORNodeType()) {
+                case XPONDER:
+                    transponderPresent = true;
+                    String nwTpId = "";
+                    if (((pathElement == 0) && (StringConstants.SERVICE_DIRECTION_AZ).equals(direction))
+                            || ((pathElement == (vertices.size() - 1)) && (StringConstants.SERVICE_DIRECTION_ZA)
+                                .equals(direction))) {
+                        //First Xponder of the path TX side
+                        nwTpId = getAppropriatePceLink((pathElement + offsetLink), edges, allPceLinks, direction)
+                            .getSourceTP().getValue();
+                    } else {
+                        // last Xponder of the path (RX side)
+                        nwTpId = getAppropriatePceLink((pathElement - offsetLink - 1), edges, allPceLinks, direction)
+                        .getDestTP().getValue();
+                    }
+                    nwTpIid = InstanceIdentifiers.createNetworkTerminationPoint1IIDBuilder(
+                            vertices.get(pathElement), nwTpId);
+                    LOG.debug("loop of check OSNR : XPDR, n = {} Path Element = {}", n, pathElement);
+                    try {
+                        if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, nwTpIid)
+                                .get().isPresent()) {
+                            XpdrNetworkAttributes xna = networkTransactionService
+                                .read(LogicalDatastoreType.CONFIGURATION, nwTpIid)
+                                .get().get().getXpdrNetworkAttributes();
+                            // If the operational mode of the Xponder is not consistent or
+                            // if the operational mode of the Xponder is not declared in the topology
+                            // (Network TP)
+                            if (currentNode.getXponderOperationalMode(xna).contentEquals(StringConstants.UNKNOWN_MODE)
+                                    || currentNode.getXponderOperationalMode(xna) == null
+                                    || currentNode.getXponderOperationalMode(xna).isEmpty()) {
+                                // Operational mode is retrieved from the service Type assuming it is supported
+                                // by the Xponder
+                                opMode = cu.getPceOperationalModeFromServiceType(
+                                    CatalogConstant.CatalogNodeType.TSP, serviceType);
+                            } else {
+                                // Operational mode is found as an attribute of the network TP
+                                opMode = currentNode.getXponderOperationalMode(xna);
+                            }
+                            LOG.debug("Transponder {} corresponding to path Element {} in the path has {} operational "
+                                    + "mode", currentNode.getNodeId().getValue(), pathElement, opMode);
+                        } else {
+                            LOG.error("Issue accessing the XponderNetworkAttributes of {} for Transponder {}"
+                                + " corresponding to path Element {} in the path ",
+                                nwTpId, currentNode.getNodeId().getValue(), pathElement);
+                            opMode = cu.getPceOperationalModeFromServiceType(
+                                CatalogConstant.CatalogNodeType.TSP, serviceType);
+                            LOG.info("Did not succeed finding network TP {} in Configuration Datastore. Retrieve"
+                                + " default Operational Mode {} from serviceType {}", nwTpId, opMode, serviceType);
+                        }
+                    } catch (InterruptedException | ExecutionException e1) {
+                        opMode = cu.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP,
+                            serviceType);
+                        LOG.info("Did not succeed finding network TP {} in Configuration Datastore. Retrieve"
+                            + " default Operational Mode {} from serviceType {}", nwTpId, opMode, serviceType);
+                    }
+                    // If TSP is the last of the path
+                    if (((pathElement == (vertices.size() - 1))
+                            && (StringConstants.SERVICE_DIRECTION_AZ).equals(direction))
+                            || ((pathElement == 0) && (StringConstants.SERVICE_DIRECTION_ZA).equals(direction))) {
+                        LOG.debug("Loop n = {}, Step5.1, XPDR, tries calculating Margin, just before call", n);
+                        // Check that accumulated degradations are compatible with TSP performances
+                        // According to OpenROADM spec :
+                        // margin = cu.getPceRxTspParameters(opMode, calcCd, Math.sqrt(calcPmd2), Math.sqrt(calcPdl2),
+                        //              getOsnrDbfromOnsrLin(calcOnsrLin));
+                        // Calculation modified for pdl according to calculation in Julia's Tool
+                        margin = cu.getPceRxTspParameters(opMode, calcCd, Math.sqrt(calcPmd2),
+                            (Math.sqrt(calcPdl2)), getOsnrDbfromOnsrLin(calcOnsrLin));
+                        LOG.info("Loop n = {}, XPDR, calcosnrdB= {}", n, getOsnrDbfromOnsrLin(calcOnsrLin));
+                    } else {
+                        // TSP is first element of the path . To correctly evaluate the TX OOB OSNR from
+                        // its operational mode, we need to know the type of ADD/DROP Mux it is
+                        // connected to
+                        String adnMode = "";
+                        // If the operational mode of the ADD/DROP MUX is not consistent or
+                        // if the operational mode of the ADD/DROP MUX is not declared in the topology
+                        // (Network TP)
+                        if (StringConstants.UNKNOWN_MODE.equals(nextNode.getOperationalMode())
+                                || nextNode.getOperationalMode() == null
+                                || nextNode.getOperationalMode().isEmpty()) {
+                            // Operational mode is set by default to standard opMode for ADD SRGs
+                            adnMode = CatalogConstant.MWWRCORE;
+                        } else {
+                            // Operational mode is found in SRG attributes of the Node
+                            adnMode = nextNode.getOperationalMode();
+                        }
+                        LOG.debug("Transponder {} corresponding to path Element {} in the path is connected to SRG "
+                            + "which has {} operational mode", currentNode.getNodeId().getValue(), pathElement,
+                            adnMode);
+                        // Retrieve the Tx ONSR of the Xponder which results from IB and OOB OSNR
+                        // contributions
+                        calcOnsrLin = cu.getPceTxTspParameters(opMode, adnMode);
+                        // Retrieve the spacing associated with Xponder operational mode that is needed
+                        // to calculate OSNR
+                        spacing = cu.getPceTxTspChannelSpacing(opMode);
+                        LOG.info("Transponder {} corresponding to path Element {} in the path has a TX OSNR of {} dB",
+                            currentNode.getNodeId().getValue(), pathElement, getOsnrDbfromOnsrLin(calcOnsrLin));
+                    }
+                    break;
+                case SRG:
+                    String srgMode = "";
+                    // If the operational mode of the ADD/DROP MUX is not consistent or
+                    // if the operational mode of the ADD/DROP MUX is not declared in the topology
+                    // (Network TP)
+                    if (StringConstants.UNKNOWN_MODE.equals(currentNode.getOperationalMode())
+                            || currentNode.getOperationalMode() == null
+                            || currentNode.getOperationalMode().isEmpty()) {
+                        // Operational mode is set by default to standard opMode for ADD/DROP SRGs
+                        srgMode = CatalogConstant.MWWRCORE;
+                    } else {
+                        // Operational mode is found in SRG attributes of the Node
+                        srgMode = currentNode.getOperationalMode();
+                    }
+                    cnt = CatalogConstant.CatalogNodeType.DROP;
+                    LOG.debug("loop of check OSNR : SRG, n = {} Path Element = {}", n, pathElement);
+                    if ((pathElement <= 1) && (StringConstants.SERVICE_DIRECTION_AZ).equals(direction)
+                            || (pathElement >= vertices.size() - 2)
+                            && (StringConstants.SERVICE_DIRECTION_ZA).equals(direction)) {
+                        // This is ADD case : First (optical-tunnel) or 2nd (Regular E2E service from
+                        // Xponder to Xponder) node element of the path is the ADD SRG.
+                        if (!(getAppropriatePceLink((pathElement + offsetLink), edges, allPceLinks, direction)
+                                .getlinkType() == OpenroadmLinkType.ADDLINK)) {
+                            LOG.error("Error processing Node {} for which output link {} is not an ADDLINK Type",
+                                currentNode.getNodeId().toString(), pathElement + offsetLink);
+                        }
+                        cnt = CatalogConstant.CatalogNodeType.ADD;
+                        pwrIn = 0.0;
+                        pwrOut = cu.getPceRoadmAmpOutputPower(cnt, srgMode,
+                            getAppropriatePceLink((pathElement + 1 + offsetLink * 3), edges, allPceLinks, direction)
+                            .getspanLoss(), spacing,
+                            getAppropriatePceLink((pathElement + 1 + offsetLink * 3), edges, allPceLinks, direction)
+                            .getpowerCorrection());
+                        LOG.debug("loop of check OSNR : SRG, n = {} link {} Pout = {}",
+                            pathElement, pathElement + 1 + offsetLink * 3, pwrOut);
+                    } else {
+                        // Other case is DROP, for which cnt is unchanged (.DROP)
+                        if (!(getAppropriatePceLink((pathElement - 1 - offsetLink), edges, allPceLinks, direction)
+                                .getlinkType() == OpenroadmLinkType.DROPLINK)) {
+                            LOG.error("Error processing Node {} for which input link {} is not a DROPLINK Type",
+                                currentNode.getNodeId().toString(), pathElement - 1 - offsetLink);
+                        }
+                        pwrIn = pwrOut - getAppropriatePceLink((pathElement - offsetLink * 3 - 2), edges, allPceLinks,
+                            direction).getspanLoss();
+                        // Calculate degradation accumulated across incoming Link and add them to
+                        // accumulated impairments
+                        calcCd += getAppropriatePceLink((pathElement - offsetLink * 3 - 2), edges, allPceLinks,
+                            direction).getcd();
+                        LOG.info("loop of check OSNR : SRG, n = {} CD on preceeding link {} = {} ps", pathElement,
+                            pathElement - offsetLink * 3 - 2, getAppropriatePceLink((pathElement - offsetLink * 3 - 2),
+                                edges, allPceLinks, direction).getcd());
+                        calcPmd2 += getAppropriatePceLink((pathElement - offsetLink * 3 - 2), edges, allPceLinks,
+                            direction).getpmd2();
+                        // This also includes Non Linear Contribution from the path
+                        calcOnsrLin += cu.calculateNLonsrContribution(pwrOut, getAppropriatePceLink((pathElement
+                            - offsetLink * 3 - 2), edges, allPceLinks, direction).getLength(), spacing);
+                    }
+                    //calculation of the SRG contribution either for Add and Drop
+                    impairments = cu.getPceRoadmAmpParameters(cnt, srgMode,
+                        pwrIn, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing);
+                    calcCd = impairments.get("CD").doubleValue();
+                    calcPmd2 = impairments.get("DGD2").doubleValue();
+                    calcPdl2 = impairments.get("PDL2").doubleValue();
+                    calcOnsrLin = impairments.get("ONSRLIN").doubleValue();
+                    if (calcOnsrLin == Double.NEGATIVE_INFINITY || calcOnsrLin == Double.POSITIVE_INFINITY) {
+                        return -1.0;
+                    }
+                    if (pathElement > 1) {
+                        // If SRG is not the first or the second element of the Path, it is the DROP
+                        // side.
+                        // After accumulated degradations are calculated, we also need to calculate
+                        // resulting OSNR in dB to pass it to the method that verifies end Xponder
+                        // performances are compatible with degradations experienced on the path
+                        try {
+                            calcOsnrdB = getOsnrDbfromOnsrLin(calcOnsrLin);
+                            LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOsnrdB);
+                            LOG.info("Loop n = {}, DROP, calcOsnrdB= {}", n, calcOsnrdB);
+                        } catch (ArithmeticException e) {
+                            LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}",
+                                path.getEdgeList().size());
+                            return -1.0;
+                        }
+                    }
+                    if (CatalogConstant.CatalogNodeType.ADD.equals(cnt)) {
+                        // For the ADD, degradation brought by the node are calculated from the MW-WR spec.
+                        // The Degree is not considered. This means we must bypass the add-link (ADD)
+                        // and the next node (Degree) which are not considered in the impairments.
+                        n++;
+                    }
+                    impairments.clear();
+                    break;
+                case DEGREE:
+                    if (nextNode.getORNodeType() != OpenroadmNodeType.DEGREE) {
+                        //This is the case of DROP, ROADM degree is not considered
+                        break;
+                    }
+                    LOG.info("loop of check OSNR : DEGREE, n = {} Path Element = {}", n, pathElement);
+                    cnt = CatalogConstant.CatalogNodeType.EXPRESS;
+                    String degree1Mode = "";
+                    String degree2Mode = "";
+                    // If the operational mode of the Degree is not consistent or if the operational
+                    // mode is not declared in the topology
+                    if (StringConstants.UNKNOWN_MODE.equals(currentNode.getOperationalMode())
+                            || currentNode.getOperationalMode() == null
+                            || currentNode.getOperationalMode().isEmpty()) {
+                        // Operational mode is set by default to standard opMode for Degree
+                        degree1Mode = CatalogConstant.MWMWCORE;
+                    } else {
+                        // Operational mode is found in degree-attributes of the Node
+                        degree1Mode = currentNode.getOperationalMode();
+                    }
+                    // Same for next node which is the second degree of a ROADM node
+                    if (StringConstants.UNKNOWN_MODE.equals(nextNode.getOperationalMode())
+                            || nextNode.getOperationalMode() == null
+                            || nextNode.getOperationalMode().isEmpty()) {
+                        degree2Mode = CatalogConstant.MWMWCORE;
+                    } else {
+                        degree2Mode = currentNode.getOperationalMode();
+                    }
+                    // At that time OpenROADM provides only one spec for the ROADM nodes
+                    if (!degree1Mode.equals(degree2Mode)) {
+                        LOG.info("Unsupported Hybrid ROADM configuration with Degree1 {} of {} operational mode"
+                            + "and Degree2 {} of {} operational mode. Will by default use operational mode"
+                            + "of Degree2", currentNode.getNodeId().toString(),
+                            degree1Mode, nextNode.getNodeId().toString(), degree2Mode);
+                    }
+                    pwrIn = pwrOut - getAppropriatePceLink((pathElement - offsetLink - 1), edges, allPceLinks,
+                        direction).getspanLoss();
+                    // Calculate degradation accumulated across incoming Link and add them to
+                    // accumulated impairments
+                    calcCd += getAppropriatePceLink((pathElement - offsetLink - 1), edges, allPceLinks, direction)
+                        .getcd();
+                    calcPmd2 += getAppropriatePceLink((pathElement - offsetLink - 1), edges, allPceLinks, direction)
+                        .getpmd2();
+                    // This also includes Non Linear Contribution from the path
+                    calcOnsrLin += cu.calculateNLonsrContribution(pwrOut, getAppropriatePceLink((pathElement
+                        - offsetLink - 1), edges, allPceLinks, direction).getLength(), spacing);
+                    // Calculate output power for next span (Output of degree 2)
+                    pwrOut = cu.getPceRoadmAmpOutputPower(cnt, degree2Mode, getAppropriatePceLink((pathElement
+                        + 3 * offsetLink + 1), edges, allPceLinks, direction).getspanLoss(), spacing,
+                        getAppropriatePceLink((pathElement + 3 * offsetLink + 1), edges, allPceLinks, direction)
+                        .getpowerCorrection());
+                    // Adds to accumulated impairments the degradation associated with the Express
+                    // path of ROADM : Degree1, express link, Degree2
+                    impairments = cu.getPceRoadmAmpParameters(cnt, degree2Mode,
+                        pwrIn, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing);
+                    calcCd = impairments.get("CD").doubleValue();
+                    calcPmd2 = impairments.get("DGD2").doubleValue();
+                    calcPdl2 = impairments.get("PDL2").doubleValue();
+                    calcOnsrLin = impairments.get("ONSRLIN").doubleValue();
+                    LOG.debug("Loop n = {}, DEGREE, calcOsnrdB= {}", n, getOsnrDbfromOnsrLin(calcOnsrLin));
+                    if (calcOnsrLin == Double.NEGATIVE_INFINITY || calcOnsrLin == Double.POSITIVE_INFINITY) {
+                        return -1.0;
+                    }
+                    // increment pathElement so that in next step we will not point to Degree2 but
+                    // next node
+                    n++;
+                    LOG.info("Accumulated degradations in the path including ROADM {} + {} are CD: {}; PMD2: "
+                        + "{}; Pdl2 : {}; ONSRdB : {}", currentNode.getNodeId().toString(),
+                        nextNode.getNodeId().toString(), calcCd, calcPmd2, calcPdl2, getOsnrDbfromOnsrLin(calcOnsrLin));
+                    break;
+                default:
+                    LOG.error("PostAlgoPathValidator.CheckOSNR : unsupported resource type in the path chain");
             }
         }
-        try {
-            osnrDb = getOsnrDb(1 / inverseLocalOsnr);
-        } catch (ArithmeticException e) {
-            LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}", path.getEdgeList().size());
-            return false;
+        LOG.info("- In checkOSNR: accumulated CD = {} ps, PMD = {} ps, PDL = {} dB, and resulting OSNR calcOsnrdB = {} "
+            + "dB and ONSR dB exterapolated from calcosnrlin = {}"
+            + " including non linear contributions",
+            calcCd, Math.sqrt(calcPmd2), Math.sqrt(calcPdl2), calcOsnrdB, getOsnrDbfromOnsrLin(calcOnsrLin));
+        if (!transponderPresent) {
+            LOG.info("No transponder in the path, User shall check from CD, PMD, and OSNR values provided "
+                + "that optical tunnel degradations are compatible with external transponder performances");
+            return 0.0;
         }
-        LOG.info("In checkOSNR: OSNR of the path is {} dB", osnrDb);
-        return ((osnrDb + SYS_MARGIN) > MIN_OSNR_W100G);
+        LOG.info("In checkOSNR: Transponder Operational mode {} results in a residual margin of {} dB, according "
+            + "to CD, PMD and DGD induced penalties and set System Margin of {} dB.",
+            opMode, margin - SYS_MARGIN, SYS_MARGIN);
+        String validationMessage = "INVALIDATED";
+        if ((margin - SYS_MARGIN) >= 0) {
+            validationMessage = "VALIDATED";
+        }
+        if ((StringConstants.SERVICE_DIRECTION_AZ).equals(direction)) {
+            LOG.info("- In checkOSNR: A to Z Path from {} to {} {}", vertices.get(0),
+                vertices.get(vertices.size() - 1), validationMessage);
+        } else {
+            LOG.info("- In checkOSNR: Z to A Path from {} to {} {}", vertices.get(vertices.size() - 1),
+                vertices.get(0), validationMessage);
+        }
+        return (margin - SYS_MARGIN);
     }
 
-    private double getOsnrDb(double osnrLu) {
-        return (10 * Math.log10(osnrLu));
+    // Method to provide either regular link (AtoZ) or Opposite link (ZtoA) in the list of PceGraphEdges
+    private PceLink getAppropriatePceLink(Integer pathEltNber, List<PceGraphEdge> edges,
+            Map<LinkId, PceLink> allPceLinks, String direction) {
+        if ((StringConstants.SERVICE_DIRECTION_AZ).equals(direction)) {
+            // Returns regular link.
+            return edges.get(pathEltNber).link();
+        }
+            //For Z to A direction, must return the opposite link
+        return allPceLinks.get(new LinkId(edges.get(pathEltNber).link()
+            .getOppositeLink()));
     }
 
-    private double getInverseOsnrLinkLu(double linkOsnrDb) {
-        // 1 over the link OSNR, in linear units
-        double linkOsnrLu = Math.pow(10, (linkOsnrDb / 10.0));
-        LOG.debug("In retrieveosnr: the inverse of link osnr is {} (Linear Unit)", linkOsnrLu);
-        return (CONST_OSNR / linkOsnrLu);
+    private double getOsnrDbfromOnsrLin(double onsrLu) {
+        return (10 * Math.log10(1 / onsrLu));
     }
 
     /**
@@ -480,4 +837,8 @@ public class PostAlgoPathValidator {
         }
         return spectrumAssignmentBldr.build();
     }
+
+    public Double getTpceCalculatedMargin() {
+        return tpceCalculatedMargin;
+    }
 }
index 2d05a3e..eb94fa6 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.transportpce.pce.networkanalyzer;
 
 import java.io.Serializable;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -65,14 +66,16 @@ public class PceLink implements Serializable {
     private final Long availableBandwidth;
     private final Long usedBandwidth;
     private final List<Long> srlgList;
-    private final double osnr;
+//    private final double osnr;
+    private final Double length;
+    private final Double cd;
+    private final Double pmd2;
+    private final Double spanLoss;
+    private final Double powerCorrection;
     private final transient Span omsAttributesSpan;
     //meter per ms
-    private static final double CELERITY = 2.99792458 * 1e5;
-    private static final double NOISE_MASK_A = 0.571429;
-    private static final double NOISE_MASK_B = 39.285714;
-    private static final double UPPER_BOUND_OSNR = 33;
-    private static final double LOWER_BOUND_OSNR = 0.1;
+    private static final double GLASSCELERITY = 2.99792458 * 1e5 / 1.5;
+    private static final double PMD_CONSTANT = 0.04;
 
     public PceLink(Link link, PceNode source, PceNode dest) {
         LOG.debug("PceLink: : PceLink start ");
@@ -100,26 +103,39 @@ public class PceLink implements Serializable {
 
         if (this.linkType == OpenroadmLinkType.ROADMTOROADM) {
             this.omsAttributesSpan = MapUtils.getOmsAttributesSpan(link);
+            this.length = calcLength(link);
             this.srlgList = MapUtils.getSRLG(link);
             this.latency = calcLatency(link);
-            this.osnr = calcSpanOSNR();
             this.availableBandwidth = 0L;
             this.usedBandwidth = 0L;
+            Map<String, Double> spanLossMap = calcSpanLoss(link);
+            this.spanLoss = spanLossMap.get("SpanLoss");
+            this.powerCorrection = spanLossMap.get("PoutCorrection");
+            Map<String, Double> cdAndPmdMap = calcCDandPMD(link);
+            this.cd = cdAndPmdMap.get("CD");
+            this.pmd2 = cdAndPmdMap.get("PMD2");
         } else if (this.linkType == OpenroadmLinkType.OTNLINK) {
             this.availableBandwidth = MapUtils.getAvailableBandwidth(link);
             this.usedBandwidth = MapUtils.getUsedBandwidth(link);
             this.srlgList = MapUtils.getSRLGfromLink(link);
-            this.osnr = 0.0;
             this.latency = 0L;
+            this.length = 0.0;
             this.omsAttributesSpan = null;
+            this.spanLoss = 0.0;
+            this.powerCorrection = 0.0;
+            this.cd = 0.0;
+            this.pmd2 = 0.0;
         } else {
             this.omsAttributesSpan = null;
             this.srlgList = null;
             this.latency = 0L;
-            //infinite OSNR in DB
-            this.osnr = 100L;
+            this.length = 0.0;
             this.availableBandwidth = 0L;
             this.usedBandwidth = 0L;
+            this.spanLoss = 0.0;
+            this.powerCorrection = 0.0;
+            this.cd = 0.0;
+            this.pmd2 = 0.0;
         }
         LOG.debug("PceLink: created PceLink  {}", linkId);
     }
@@ -134,63 +150,145 @@ public class PceLink implements Serializable {
         return tmpoppositeLink;
     }
 
-    //Compute the link latency : if the latency is not defined, the latency is computed from the omsAttributesSpan
+    //Compute the link latency : if the latency is not defined, the latency is computed from the length
     private Long calcLatency(Link link) {
         Link1 link1 = link.augmentation(Link1.class);
         if (link1.getLinkLatency() != null) {
             return link1.getLinkLatency().toJava();
         }
-        if (this.omsAttributesSpan == null) {
+        Double linkLength = calcLength(link);
+        if (linkLength == null) {
+            LOG.debug("In PceLink: cannot compute the latency for the link {}", link.getLinkId().getValue());
             return 1L;
         }
-        double tmp = 0;
+        LOG.debug("In PceLink: The latency of link {} is extrapolated from link length and == {}",
+            link.getLinkId(), linkLength / GLASSCELERITY);
+        return (long) Math.ceil(linkLength / GLASSCELERITY);
+    }
+
+    private Double calcLength(Link link) {
+        Link1 link1 = link.augmentation(Link1.class);
+        if (link1.getLinkLength() != null) {
+            return link1.getLinkLength().doubleValue();
+        }
+        if (this.omsAttributesSpan == null) {
+            LOG.debug("In PceLink: cannot compute the length for the link {}", link.getLinkId().getValue());
+            return null;
+        }
+        double linkLength = 0;
         Map<LinkConcatenationKey, LinkConcatenation> linkConcatenationMap = this.omsAttributesSpan
-                .nonnullLinkConcatenation();
+            .nonnullLinkConcatenation();
         for (Map.Entry<LinkConcatenationKey, LinkConcatenation> entry : linkConcatenationMap.entrySet()) {
-            // Length is expressed in meter and latency is expressed in ms according to OpenROADM MSA
+            // Length is expressed in meter according to OpenROADM MSA
             if (entry == null || entry.getValue() == null || entry.getValue().getSRLGLength() == null) {
                 LOG.debug("In PceLink: cannot compute the latency for the link {}", link.getLinkId().getValue());
-                return 1L;
+                return null;
+            }
+            linkLength += entry.getValue().getSRLGLength().doubleValue();
+            LOG.debug("In PceLink: The length of the link {} == {}", link.getLinkId(), linkLength / 1000.0);
+        }
+        return (linkLength / 1000.0);
+    }
+
+    //Calculate CD and PMD of the link from link length
+    private Map<String, Double> calcCDandPMDfromLength() {
+        Map<String, Double> cdAndPmd = new HashMap<>();
+        if (this.length != null) {
+            cdAndPmd.put("CD", 16.5 * this.length);
+            cdAndPmd.put("PMD2", Math.pow(this.length * PMD_CONSTANT, 2));
+        }
+        return cdAndPmd;
+    }
+
+    //Calculate CD and PMD of the link
+    private Map<String, Double> calcCDandPMD(Link link) {
+        double linkCd = 0.0;
+        double linkPmd2 = 0.0;
+        if (this.omsAttributesSpan == null) {
+            LOG.debug("In PceLink {} no OMS present, assume G.652 fiber, calculation based on fiber length of {} km",
+                link.getLinkId(), this.length);
+            return calcCDandPMDfromLength();
+        }
+        Map<LinkConcatenationKey, LinkConcatenation> linkConcatenationMap = this.omsAttributesSpan
+            .nonnullLinkConcatenation();
+        for (Map.Entry<LinkConcatenationKey, LinkConcatenation> entry : linkConcatenationMap.entrySet()) {
+            // If the link-concatenation list is not populated or partially populated CD &
+            // PMD shall be derived from link-length (expressed in km in OR topology)
+            if (entry == null || entry.getValue() == null || entry.getValue().getSRLGLength() == null
+                    || entry.getValue().augmentation(LinkConcatenation1.class).getFiberType() == null) {
+                if (this.length > 0.0) {
+                    LOG.debug("In PceLink: no OMS present; cd and PMD for the link {} extrapolated from link length {}"
+                        + "assuming SMF fiber type", link.getLinkId().getValue(), this.length);
+                    return calcCDandPMDfromLength();
+                }
+                // If Link-length upper attributes not present or incorrectly populated, no way
+                // to calculate CD & PMD
+                LOG.error("In PceLink: no Link length declared and no OMS present for the link {}."
+                    + " No Way to compute CD and PMD", link.getLinkId().getValue());
+                return Map.of();
+            }
+            // SRLG length is expressed in OR topology in meter
+            linkCd += entry.getValue().getSRLGLength().doubleValue() / 1000.0 * retrieveCdFromFiberType(
+                entry.getValue().augmentation(LinkConcatenation1.class).getFiberType());
+            if (entry.getValue().augmentation(LinkConcatenation1.class).getPmd() == null
+                    || entry.getValue().augmentation(LinkConcatenation1.class).getPmd().getValue().doubleValue() == 0.0
+                    || entry.getValue().augmentation(LinkConcatenation1.class).getPmd().getValue()
+                    .toString().isEmpty()) {
+                linkPmd2 += Math.pow(entry.getValue().getSRLGLength().doubleValue() / 1000.0
+                    * retrievePmdFromFiberType(entry.getValue().augmentation(LinkConcatenation1.class)
+                    .getFiberType()),2);
+            } else {
+                linkPmd2 += Math
+                    .pow(entry.getValue().augmentation(LinkConcatenation1.class).getPmd().getValue().doubleValue(), 2);
             }
-            tmp += entry.getValue().getSRLGLength().doubleValue() / CELERITY;
-            LOG.debug("In PceLink: The latency of link {} == {}", link.getLinkId(), tmp);
         }
-        return (long) Math.ceil(tmp);
+        LOG.debug("In PceLink: The CD and PMD2 of link {} are respectively {} ps and {} ps", link.getLinkId(), linkCd,
+            linkPmd2);
+        return Map.of("CD", linkCd,"PMD2", linkPmd2);
+    }
+
+    // compute default spanLoss and power correction from fiber length
+    // when no OMS attribute defined
+    private Map<String, Double> calcDefaultSpanLoss(Link link) {
+        Map<String, Double> omsExtrapolatedCharac = new HashMap<>();
+        Link1 link1 = link.augmentation(Link1.class);
+        if (link1.getLinkLength() == null || link1.getLinkLength().doubleValue() == 0) {
+            LOG.error("In PceLink, no link length present or length declared = 0,"
+                + " unable to calculate default span Loss ");
+            return omsExtrapolatedCharac;
+        }
+        long linkLength = link1.getLinkLength().longValue();
+        LOG.warn("In PceLink {}, assume G.652 fiber, calculation "
+            + "based on fiber length of {} km and typical loss of 0.25dB per Km ",
+            link.getLinkId(), linkLength);
+        omsExtrapolatedCharac.put("SpanLoss", linkLength * 0.25);
+        omsExtrapolatedCharac.put("PoutCorrection", retrievePower(FiberType.Smf));
+        return omsExtrapolatedCharac;
     }
 
-    //Compute the OSNR of a span
-    private double calcSpanOSNR() {
+    // Compute the attenuation of a span from OMS attribute
+    private Map<String, Double> calcSpanLoss(Link link) {
         if (this.omsAttributesSpan == null) {
-            return 0L;
+            return calcDefaultSpanLoss(link);
         }
-        Collection<LinkConcatenation> linkConcatenationList =
-            this.omsAttributesSpan.nonnullLinkConcatenation().values();
+        Collection<LinkConcatenation> linkConcatenationList = this.omsAttributesSpan.nonnullLinkConcatenation()
+            .values();
         if (linkConcatenationList == null) {
             LOG.error("in PceLink : Null field in the OmsAttrubtesSpan");
-            return 0L;
+            return calcDefaultSpanLoss(link);
         }
         Iterator<LinkConcatenation> linkConcatenationiterator = linkConcatenationList.iterator();
         if (!linkConcatenationiterator.hasNext()) {
-            return 0L;
+            return calcDefaultSpanLoss(link);
         }
-        if (this.omsAttributesSpan.getSpanlossCurrent() == null) {
-            LOG.error("in PceLink : Spanloss is null");
-            return 0L;
-        }
-        // power on the output of the previous ROADM (dBm)
-        double pout = retrievePower(linkConcatenationiterator.next().augmentation(LinkConcatenation1.class)
-            .getFiberType());
-        // span loss (dB)
-        double spanLoss = this.omsAttributesSpan.getSpanlossCurrent().getValue().doubleValue();
-        // power on the input of the current ROADM (dBm)
-        double pin = pout - spanLoss;
-        double spanOsnrDb = NOISE_MASK_A * pin + NOISE_MASK_B;
-        if (spanOsnrDb > UPPER_BOUND_OSNR) {
-            spanOsnrDb = UPPER_BOUND_OSNR;
-        } else if (spanOsnrDb < LOWER_BOUND_OSNR) {
-            spanOsnrDb = LOWER_BOUND_OSNR;
-        }
-        return spanOsnrDb;
+        // Reference of power to be launched at input of ROADM (dBm)
+        Map<String, Double> omsCharacteristics = new HashMap<>();
+        omsCharacteristics.put("PoutCorrection",
+            retrievePower(linkConcatenationiterator.next().augmentation(LinkConcatenation1.class)
+                .getFiberType()) - 2.0);
+        // span loss of the span
+        omsCharacteristics.put("SpanLoss", this.omsAttributesSpan.getSpanlossCurrent().getValue().doubleValue());
+        return omsCharacteristics;
     }
 
     private double retrievePower(FiberType fiberType) {
@@ -217,6 +315,48 @@ public class PceLink implements Serializable {
         return power;
     }
 
+    private double retrievePmdFromFiberType(FiberType fiberType) {
+        if (fiberType.toString().equalsIgnoreCase("Dsf")) {
+            return 0.2;
+        } else {
+            return PMD_CONSTANT;
+        }
+    }
+
+    private double retrieveCdFromFiberType(FiberType fiberType) {
+        double cdPerKm;
+        switch (fiberType) {
+            case Smf:
+                cdPerKm = 16.5;
+                break;
+            case Eleaf:
+                cdPerKm = 4.3;
+                break;
+            case Truewavec:
+                cdPerKm = 3.0;
+                break;
+            case Oleaf:
+                cdPerKm = 4.3;
+                break;
+            case Dsf:
+                cdPerKm = 0.0;
+                break;
+            case Truewave:
+                cdPerKm = 4.4;
+                break;
+            case NzDsf:
+                cdPerKm = 4.3;
+                break;
+            case Ull:
+                cdPerKm = 16.5;
+                break;
+            default:
+                cdPerKm = 16.5;
+                break;
+        }
+        return cdPerKm;
+    }
+
     public LinkId getOppositeLink() {
         return oppositeLink;
     }
@@ -257,6 +397,10 @@ public class PceLink implements Serializable {
         return client;
     }
 
+    public Double getLength() {
+        return length;
+    }
+
     public void setClient(String client) {
         this.client = client;
     }
@@ -286,10 +430,6 @@ public class PceLink implements Serializable {
         return srlgList;
     }
 
-    public double getosnr() {
-        return osnr;
-    }
-
     public String getsourceCLLI() {
         return sourceCLLI;
     }
@@ -298,6 +438,22 @@ public class PceLink implements Serializable {
         return destCLLI;
     }
 
+    public Double getspanLoss() {
+        return spanLoss;
+    }
+
+    public Double getcd() {
+        return cd;
+    }
+
+    public Double getpmd2() {
+        return pmd2;
+    }
+
+    public Double getpowerCorrection() {
+        return powerCorrection;
+    }
+
     public boolean isValid() {
         if ((this.linkId == null) || (this.linkType == null) || (this.oppositeLink == null)) {
             isValid = false;
@@ -305,15 +461,19 @@ public class PceLink implements Serializable {
         }
         isValid = checkParams();
         if (this.linkType == OpenroadmLinkType.ROADMTOROADM) {
-            if (this.omsAttributesSpan == null) {
+            if ((this.length == null || this.length == 0.0)
+                    && this.omsAttributesSpan == null) {
                 isValid = false;
-                LOG.error("PceLink: Error reading Span for OMS link. Link is ignored {}", linkId);
-            } else if (this.omsAttributesSpan.getSpanlossCurrent() == null) {
+                LOG.error("PceLink: Error reading Span for OMS link, and no available generic link information."
+                    + " Link is ignored {}", linkId);
+            } else if ((this.length == null || this.length == 0.0)
+                    && this.omsAttributesSpan.getSpanlossCurrent() == null) {
                 isValid = false;
-                LOG.error("PceLink: Error reading Spanloss for OMS link. Link is ignored {}", linkId);
+                LOG.error("PceLink: Error reading Span for OMS link, and no available generic link information."
+                    + " Link is ignored {}", linkId);
             }
         }
-        if ((this.srlgList != null) && (this.srlgList.isEmpty())) {
+        if (this.srlgList != null && this.srlgList.isEmpty()) {
             isValid = false;
             LOG.error("PceLink: Empty srlgList for OMS link. Link is ignored {}", linkId);
         }
@@ -352,7 +512,7 @@ public class PceLink implements Serializable {
                     return false;
                 }
                 neededBW = 300000L;
-                // hange otn-link-type
+                // change otn-link-type
                 neededType = OtnLinkType.OTUC3;
                 break;
             case "ODUC4":
index 5573ad6..5dc2184 100644 (file)
@@ -14,6 +14,8 @@ import java.util.List;
 import java.util.Map;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.termination.point.XpdrNetworkAttributes;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmNodeType;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
 import org.opendaylight.yangtools.yang.common.Uint16;
 
@@ -40,6 +42,12 @@ public interface PceNode {
 
     NodeId getNodeId();
 
+    OpenroadmNodeType getORNodeType();
+
+    String getOperationalMode();
+
+    String getXponderOperationalMode(XpdrNetworkAttributes tp);
+
     Map<String, List<Uint16>> getAvailableTribPorts();
 
     Map<String, List<Uint16>> getAvailableTribSlots();
index e5b5b4c..67ce46b 100644 (file)
@@ -17,6 +17,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.TreeMap;
+import org.opendaylight.transportpce.common.StringConstants;
 import org.opendaylight.transportpce.common.fixedflex.GridConstant;
 import org.opendaylight.transportpce.common.mapping.PortMapping;
 import org.opendaylight.transportpce.pce.SortPortsByName;
@@ -26,6 +27,7 @@ import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.Node1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.termination.point.XpdrNetworkAttributes;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmNodeType;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmTpType;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.available.freq.map.AvailFreqMapsKey;
@@ -34,6 +36,8 @@ import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev201211.IfOC
 import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev201211.IfOtsiOtsigroup;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev201211.SupportedIfCapability;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.xponder.rev211210.xpdr.mode.attributes.supported.operational.modes.OperationalMode;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.xponder.rev211210.xpdr.mode.attributes.supported.operational.modes.OperationalModeKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
 import org.opendaylight.yangtools.yang.common.Uint16;
@@ -364,6 +368,60 @@ public class PceOpticalNode implements PceNode {
         return client.get();
     }
 
+    @Override
+    public String getOperationalMode() {
+        Node1 node1 = this.node.augmentation(Node1.class);
+        if (node1 == null) {
+            LOG.warn("No openroadm node available for node {}", node);
+            return "";
+        }
+        switch (this.nodeType) {
+            case SRG :
+                if (node1.getSrgAttributes().getSupportedOperationalModes() == null
+                        || node1.getSrgAttributes().getSupportedOperationalModes().stream().findFirst().isEmpty()) {
+                    LOG.debug("getOperationalMode: SRG has no operational mode declared");
+                    return StringConstants.UNKNOWN_MODE;
+                } else {
+                    LOG.debug("getOperationalMode: SRG has operational mode declared {}",
+                        node1.getSrgAttributes().getSupportedOperationalModes().stream().findFirst().toString());
+                    return node1.getSrgAttributes().getSupportedOperationalModes().stream().findFirst().toString();
+                }
+            case DEGREE :
+                if (node1.getDegreeAttributes().getSupportedOperationalModes() == null
+                        || node1.getDegreeAttributes().getSupportedOperationalModes().stream().findFirst().isEmpty()) {
+                    LOG.debug("getOperationalMode: DEGREE has no operational mode declared");
+                    return StringConstants.UNKNOWN_MODE;
+                } else {
+                    LOG.debug("getOperationalMode: DEGREE has operational mode declared {}",
+                        node1.getDegreeAttributes().getSupportedOperationalModes().stream().findFirst().toString());
+                    return node1.getDegreeAttributes().getSupportedOperationalModes().stream().findFirst().toString();
+                }
+            default:
+                LOG.debug("getOperationalMode: Did not succeed retrieving Operational Mode for the node");
+                return "";
+        }
+    }
+
+    @Override
+    public String getXponderOperationalMode(XpdrNetworkAttributes tp) {
+        if (tp.getSupportedOperationalModes() == null) {
+            LOG.warn("getOperationalMode: NetworkPort {} has no operational mode declared compatible with service type",
+                tp);
+            return StringConstants.UNKNOWN_MODE;
+        }
+        for (Map.Entry<OperationalModeKey, OperationalMode> mode : tp.getSupportedOperationalModes()
+                .getOperationalMode().entrySet()) {
+            if (mode.getKey().toString().contains(StringConstants.SERVICE_TYPE_RATE
+                    .get(this.serviceType).toCanonicalString())) {
+                LOG.info("getOperationalMode: NetworkPort {}  has {} operational mode declared", tp,
+                    mode.getKey().toString());
+                return mode.getKey().toString();
+            }
+        }
+        LOG.warn("getOperationalMode: NetworkPort {}  has no operational mode declared compatible with service type",
+            tp);
+        return StringConstants.UNKNOWN_MODE;
+    }
 
     public void validateAZxponder(String anodeId, String znodeId, ServiceFormat serviceFormat) {
         if (!isValid() || this.nodeType != OpenroadmNodeType.XPONDER) {
@@ -375,7 +433,8 @@ public class PceOpticalNode implements PceNode {
             initXndrTps(serviceFormat);
             return;
         }
-        LOG.debug("validateAZxponder: XPONDER is ignored == {}", nodeId.getValue());
+        LOG.debug("validateAZxponder: XPONDER == {} is ignored, supported by {} for aNodeId {} ", nodeId.getValue(),
+            this.getSupNetworkNodeId(), anodeId);
         valid = false;
     }
 
@@ -449,6 +508,11 @@ public class PceOpticalNode implements PceNode {
         return null;
     }
 
+    @Override
+    public OpenroadmNodeType getORNodeType() {
+        return this.nodeType;
+    }
+
     @Override
     public Map<String, List<Uint16>> getAvailableTribSlots() {
         return null;
index 87ea107..40bf23c 100644 (file)
@@ -21,6 +21,7 @@ import java.util.stream.Collectors;
 import org.opendaylight.transportpce.common.StringConstants;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.termination.point.XpdrNetworkAttributes;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev201211.xpdr.odu.switching.pools.OduSwitchingPools;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev201211.xpdr.odu.switching.pools.odu.switching.pools.NonBlockingList;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmNodeType;
@@ -566,6 +567,21 @@ public class PceOtnNode implements PceNode {
         return null;
     }
 
+    @Override
+    public String getXponderOperationalMode(XpdrNetworkAttributes tp) {
+        return null;
+    }
+
+    @Override
+    public String getOperationalMode() {
+        return null;
+    }
+
+    @Override
+    public OpenroadmNodeType getORNodeType() {
+        return this.nodeType;
+    }
+
     /*
     * (non-Javadoc)
     *
index 7bf9fae..2d60bee 100644 (file)
 
 package org.opendaylight.transportpce.pce.graph;
 
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.stream.JsonReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.eclipse.jdt.annotation.NonNull;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.MountPoint;
+import org.opendaylight.mdsal.binding.api.MountPointService;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.NetworkUtils;
 import org.opendaylight.transportpce.common.StringConstants;
-import org.opendaylight.transportpce.common.fixedflex.GridConstant;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManagerImpl;
 import org.opendaylight.transportpce.common.mapping.PortMapping;
+import org.opendaylight.transportpce.common.mapping.PortMappingImpl;
+import org.opendaylight.transportpce.common.mapping.PortMappingVersion121;
+import org.opendaylight.transportpce.common.mapping.PortMappingVersion221;
+import org.opendaylight.transportpce.common.mapping.PortMappingVersion710;
+import org.opendaylight.transportpce.common.network.NetworkTransactionImpl;
+import org.opendaylight.transportpce.common.network.NetworkTransactionService;
+import org.opendaylight.transportpce.common.network.RequestProcessor;
 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
+import org.opendaylight.transportpce.pce.networkanalyzer.PceCalculation;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceLink;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceNode;
-import org.opendaylight.transportpce.pce.networkanalyzer.PceOpticalNode;
+//import org.opendaylight.transportpce.pce.networkanalyzer.PceOpticalNode;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceOtnNode;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
+import org.opendaylight.transportpce.pce.utils.JsonUtil;
 import org.opendaylight.transportpce.pce.utils.NodeUtils;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.transportpce.test.converter.DataObjectConverter;
+import org.opendaylight.transportpce.test.converter.JSONDataObjectConverter;
+import org.opendaylight.transportpce.test.stub.MountPointServiceStub;
+import org.opendaylight.transportpce.test.stub.MountPointStub;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestInput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestInputBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.computation.request.input.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.computation.request.input.ServiceZEndBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.port.PortBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev211210.OpenroadmVersionType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev211210.Node1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.TerminationPoint1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.termination.point.XpdrNetworkAttributesBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmNodeType;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmTpType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev211210.constraints.CoRoutingBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev211210.constraints.co.routing.ServiceIdentifierListBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev211210.routing.constraints.HardConstraintsBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev211210.routing.constraints.SoftConstraintsBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.OperationalModeCatalog;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.PceMetric;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.endpoint.sp.RxDirectionBuilder;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.endpoint.sp.TxDirectionBuilder;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.handler.header.ServiceHandlerHeaderBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.node.SupportingNode;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.node.SupportingNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.node.SupportingNodeKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class PceGraphTest {
-
-    private Link link = null;
+public class PceGraphTest extends AbstractTest {
+    private static final Logger LOG = LoggerFactory.getLogger(PceGraphTest.class);
+    private Link link1 = null;
     private Node node = null;
-    private PceLink pceLink = null;
+    private PceLink pceLink1 = null;
     private PceGraph pceGraph = null;
     private PceConstraints pceHardConstraints = null;
     private PceResult rc = null;
-    private PceOpticalNode pceOpticalNode = null;
-    private PceOpticalNode pceOpticalNode2 = null;
     private Map<NodeId, PceNode> allPceNodes = null;
-    private String deviceNodeId = "device node";
-    private String serviceType = "100GE";
-    @Mock
+    private Map<LinkId, PceLink> allPceLinks = null;
+    private static final String CATALOG_FILE = "src/test/resources/apidocCatalog10_1OptSpecV5_1.json";
+    private static final String MAPPING_FILE = "src/test/resources/topologyData/portMapping2.json";
+    private static OperationalModeCatalog omCatalog;
+    private static org.opendaylight.yang.gen.v1.http.org.opendaylight
+            .transportpce.portmapping.rev220316.Network networkNode;
+    private DataBroker dataBroker;
+    private MountPoint mountPoint;
+    private MountPointService mountPointService;
+    private DeviceTransactionManager deviceTransactionManager;
+    private PortMappingVersion710 portMappingVersion710;
+    private PortMappingVersion221 portMappingVersion22;
+    private PortMappingVersion121 portMappingVersion121;
     private PortMapping portMapping;
+    private RequestProcessor reqProc;
+    private NetworkTransactionService netTransServ;
+
+    // Test of integration for PceGraph
 
     @Before
-    public void setUp() {
+    public void setUp() throws InterruptedException, ExecutionException {
+        // PortMapping is instantiated to create the mapping of the different nodes in the topology
+        this.dataBroker =  getNewDataBroker();
+        this.mountPoint = new MountPointStub(dataBroker);
+        this.mountPointService = new MountPointServiceStub(mountPoint);
+        this.deviceTransactionManager = new DeviceTransactionManagerImpl(mountPointService, 3000);
+        this.portMappingVersion22 = new PortMappingVersion221(dataBroker, deviceTransactionManager);
+        this.portMappingVersion121 = new PortMappingVersion121(dataBroker, deviceTransactionManager);
+        this.portMappingVersion710 = new PortMappingVersion710(dataBroker, deviceTransactionManager);
+        this.portMapping = new PortMappingImpl(dataBroker, this.portMappingVersion710,
+            this.portMappingVersion22, this.portMappingVersion121);
+        //  The catalog of operational mode needs to be loaded so that Ctalog primitives (CatlogUtils)
+        // can retrieve physical parameters of the nodes of the path
+        DataObjectConverter dataObjectConverter = JSONDataObjectConverter
+            .createWithDataStoreUtil(getDataStoreContextUtil());
+        try (Reader reader = new FileReader(CATALOG_FILE, StandardCharsets.UTF_8)) {
+            NormalizedNode normalizedNode = dataObjectConverter
+                .transformIntoNormalizedNode(reader).get();
+            omCatalog = (OperationalModeCatalog) getDataStoreContextUtil()
+                .getBindingDOMCodecServices().fromNormalizedNode(YangInstanceIdentifier
+                    .of(OperationalModeCatalog.QNAME), normalizedNode)
+                .getValue();
+            @NonNull
+            WriteTransaction newWriteOnlyTransaction = dataBroker.newWriteOnlyTransaction();
+            newWriteOnlyTransaction
+                .put(LogicalDatastoreType.CONFIGURATION,
+                    InstanceIdentifier.create(OperationalModeCatalog.class),
+                    omCatalog);
+            newWriteOnlyTransaction.commit().get();
+        } catch (IOException e) {
+            LOG.error("Cannot load OpenROADM part of Operational Mode Catalog ", e);
+            fail("Cannot load openROADM operational modes ");
+        }
+        // The mapping corresponding to the topology is directly populated from a file in the Dta Store
+        try (Reader reader = new FileReader(MAPPING_FILE, StandardCharsets.UTF_8)) {
+            NormalizedNode normalizedNode = dataObjectConverter
+                .transformIntoNormalizedNode(reader).get();
+            networkNode = (org.opendaylight.yang.gen.v1.http.org.opendaylight
+                .transportpce.portmapping.rev220316.Network) getDataStoreContextUtil()
+                .getBindingDOMCodecServices().fromNormalizedNode(YangInstanceIdentifier
+                    .of(org.opendaylight.yang.gen.v1.http.org.opendaylight
+                        .transportpce.portmapping.rev220316.Network.QNAME), normalizedNode)
+                .getValue();
+            @NonNull
+            WriteTransaction newWriteOnlyTransaction = dataBroker.newWriteOnlyTransaction();
+            newWriteOnlyTransaction
+                .put(LogicalDatastoreType.CONFIGURATION,
+                    InstanceIdentifier.create(org.opendaylight.yang.gen.v1.http.org.opendaylight
+                        .transportpce.portmapping.rev220316.Network.class),
+                    networkNode);
+            newWriteOnlyTransaction.commit().get();
+        } catch (IOException e) {
+            LOG.error("Cannot load OpenROADM part of Operational Mode Catalog ", e);
+            fail("Cannot load openROADM operational modes ");
+        }
+
         MockitoAnnotations.openMocks(this);
-        // Build Link
-        link = NodeUtils.createRoadmToRoadm("OpenROADM-3-2-DEG1",
-                "OpenROADM-3-1-DEG1",
-                "DEG1-TTP-TX", "DEG1-TTP-RX").build();
-
-        NodeId nodeId = new NodeId("OpenROADM-3-2-DEG1");
-        node = NodeUtils.getNodeBuilder(NodeUtils.geSupportingNodes())
-                .setNodeId(nodeId).withKey(new NodeKey(nodeId))
-                .build();
-        pceOpticalNode = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
-                OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
-                GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
-        NodeId nodeId2 = new NodeId("OpenROADM-3-1-DEG1");
-        Node node2 = NodeUtils.getNodeBuilder(NodeUtils.geSupportingNodes())
-                .setNodeId(nodeId2).withKey(new NodeKey(nodeId2)).build();
-        pceOpticalNode2 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node2,
-                OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
-                GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
-        pceLink = new PceLink(link, pceOpticalNode, pceOpticalNode2);
-        pceLink.setClient("XPONDER-CLIENT");
-
-        pceLink.getDestId();
-        pceOpticalNode.addOutgoingLink(pceLink);
+        // The topology (openROADM-Network and openROADM-topology layers) is loaded from a file
+        JsonReader networkReader = null;
+        JsonReader topoReader = null;
+
+        try {
+            // load openroadm-network
+            Reader gnpyNetwork = new FileReader("src/test/resources/gnpy/gnpy_network.json",
+                    StandardCharsets.UTF_8);
+            networkReader = new JsonReader(gnpyNetwork);
+            Networks networks = (Networks) JsonUtil.getInstance().getDataObjectFromJson(networkReader,
+                    QName.create("urn:ietf:params:xml:ns:yang:ietf-network", "2018-02-26", "networks"));
+            saveOpenRoadmNetwork(networks.getNetwork().values().iterator().next(), NetworkUtils.UNDERLAY_NETWORK_ID);
+            // load openroadm-topology
+            Reader gnpyTopo = new FileReader("src/test/resources/topologyData/or-base-topology.json",
+                    StandardCharsets.UTF_8);
+            topoReader = new JsonReader(gnpyTopo);
+            networks = (Networks) JsonUtil.getInstance().getDataObjectFromJson(topoReader,
+                    QName.create("urn:ietf:params:xml:ns:yang:ietf-network", "2018-02-26", "networks"));
+            saveOpenRoadmNetwork(networks.getNetwork().values().iterator().next(), NetworkUtils.OVERLAY_NETWORK_ID);
+        } catch (IOException | InterruptedException | ExecutionException e) {
+            LOG.error("Cannot init test ", e);
+            fail("Cannot init test ");
+
+        } finally {
+            try {
+                if (networkReader != null) {
+                    networkReader.close();
+                }
+                if (topoReader != null) {
+                    topoReader.close();
+                }
+            } catch (IOException e) {
+                LOG.warn("Cannot close reader ", e);
+            }
+        }
 
         // init PceHardContraints
         pceHardConstraints = new PceConstraints();
-        // pceHardConstraints.setp
-        allPceNodes = Map.of(nodeId, pceOpticalNode, nodeId2, pceOpticalNode2);
-        rc = new PceResult();
-        pceGraph = new PceGraph(pceOpticalNode, pceOpticalNode2, allPceNodes,
-                pceHardConstraints,
-                null, rc,
-                StringConstants.SERVICE_TYPE_ODU4);
+
+        this.rc = new PceResult();
+        this.reqProc = new RequestProcessor(dataBroker);
+        this.netTransServ = new NetworkTransactionImpl(reqProc);
+
+        LOG.info("The value of the mapping is {}", portMapping);
+
     }
 
+//                       TOPOLOGY ON WHICH TEST ARE BASED
+//           _____                      _____                       _____
+//          |     | 20dB, 100km,PMD 2  |     | 20dB,100km, PMD 2   |     |
+//          |  1  |____________________|  2  |_____________________|  5  |
+//          |     |                    |     |                     |     |
+//          |_____|                    |_____|                     |_____|
+//              |___________      10km    |   20dB,100km,PMD32    /   |  100 km
+//                          |      5dB    |   _________|_________/    |  25 dB
+//                          |     PMD32 __|__/                      __|__PMD 2.0
+//        28dB, 100km,PMD 0 |          |     | 25dB,100km, PMD 2   |     |
+//                          |__________|  3  |_____________________|  4  |
+//                                     |     |                     |     |
+//                                     |_____|                     |_____|
+//
     @Test
-    public void clacPath() {
+    public void clacPath100GE() {
 
+        PceCalculation pceCalc = new PceCalculation(getPCE1Request(Uint32.valueOf(100), ServiceFormat.Ethernet,
+            "XPONDER-1", "Node1", "Client-1", "XPONDER-3", "Node3", "Client-1"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ);
         Assert.assertEquals(pceGraph.calcPath(), true);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getmargin()),
+            Optional.ofNullable(3.0919881995992924));
     }
 
     @Test
-    public void clacPathPropagationDelay() {
-        pceHardConstraints.setPceMetrics(PceMetric.PropagationDelay);
-        pceGraph.setConstrains(pceHardConstraints, null);
+    public void clacPathOTUC2() {
 
+        PceCalculation pceCalc = new PceCalculation(getPCE1Request(Uint32.valueOf(200), ServiceFormat.Ethernet,
+            "XPONDER-1", "Node1", "XPDR-NW1-TX", "XPONDER-4", "Node4", "XPDR-NW1-RX"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_OTUC2, netTransServ);
         Assert.assertEquals(pceGraph.calcPath(), true);
-        Assert.assertEquals(Optional.ofNullable(pceGraph.getPathAtoZ().get(0).getLatency()),
-                Optional.ofNullable(30.0));
-        Assert.assertEquals(pceGraph.getReturnStructure().getRate(), -1);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getmargin()),
+            Optional.ofNullable(1.1559963686478447));
     }
 
     @Test
-    public void clacPath100GE() {
-        pceGraph = new PceGraph(pceOpticalNode, pceOpticalNode2, allPceNodes,
-                pceHardConstraints,
-                null, rc,
-                StringConstants.SERVICE_TYPE_100GE_T);
+    public void clacPathOTUC3() {
+
+        PceCalculation pceCalc = new PceCalculation(getPCE1Request(Uint32.valueOf(300), ServiceFormat.Ethernet,
+            "XPONDER-1", "Node1", "XPDR-NW1-TX", "XPONDER-3", "Node3", "XPDR-NW1-RX"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_OTUC3, netTransServ);
+        Assert.assertEquals(pceGraph.calcPath(), true);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getmargin()),
+            Optional.ofNullable(0.3351048800367167));
+    }
 
+    @Test
+    public void clacUnfeasiblePath400GE() {
+
+        PceCalculation pceCalc = new PceCalculation(getPCE1Request(Uint32.valueOf(400), ServiceFormat.Ethernet,
+            "XPONDER-1", "Node1", "Client-1", "XPONDER-3", "Node3", "Client-1"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_400GE, netTransServ);
         Assert.assertEquals(pceGraph.calcPath(), false);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getmargin()),
+            Optional.ofNullable(0.0));
+    }
+
+    @Test
+    public void clacPath400GE() {
+
+        PceCalculation pceCalc = new PceCalculation(getPCE1Request(Uint32.valueOf(400), ServiceFormat.Ethernet,
+            "XPONDER-1", "Node1", "Client-1", "XPONDER-5", "Node5", "Client-1"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_400GE, netTransServ);
+        Assert.assertEquals(pceGraph.calcPath(), true);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getmargin()),
+            Optional.ofNullable(1.4432381874659086));
+    }
+
+    @Test
+    public void clacPathOTUC4() {
+
+        PceCalculation pceCalc = new PceCalculation(getPCE1Request(Uint32.valueOf(400), ServiceFormat.Ethernet,
+            "XPONDER-1", "Node1", "XPDR-NW1-TX", "XPONDER-5", "Node5", "XPDR-NW1-RX"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_OTUC4, netTransServ);
+        Assert.assertEquals(pceGraph.calcPath(), true);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getmargin()),
+            Optional.ofNullable(1.4432381874659086));
+    }
+
+    @Test
+    public void clacOpticalTunnelOTUC4() {
+
+        PceCalculation pceCalc = new PceCalculation(getPCE1Request(Uint32.valueOf(400), ServiceFormat.OC,
+            "OpenROADM-1", "Node1", "DEG1-PP-TX", "OpenROADM-5", "Node5", "DEG3-PP-TX"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_OTUC4, netTransServ);
+        Assert.assertEquals(pceGraph.calcPath(), true);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getmargin()),
+            Optional.ofNullable(0.0));
+    }
+
+    @Test
+    public void clacPath100GEnoPort() {
+
+        PceCalculation pceCalc = new PceCalculation(getPCE2Request(Uint32.valueOf(100), ServiceFormat.Ethernet,
+            "XPONDER-1", "Node1", "Client-1", "XPONDER-3", "Node3", "Client-1"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ);
+        Assert.assertEquals(pceGraph.calcPath(), true);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getmargin()),
+            Optional.ofNullable(3.0919881995992924));
+    }
+
+    @Test
+    public void clacPathPropagationDelay() {
+        PceCalculation pceCalc = new PceCalculation(getPCE1Request(Uint32.valueOf(100), ServiceFormat.Ethernet,
+            "XPONDER-1", "Node1", "Client-1", "XPONDER-3", "Node3", "Client-1"),
+            netTransServ, pceHardConstraints, null, rc, portMapping);
+        pceCalc.retrievePceNetwork();
+        pceHardConstraints.setPceMetrics(PceMetric.PropagationDelay);
+        pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
+            pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
+            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ);
+        pceGraph.setConstrains(pceHardConstraints, null);
+
+        Assert.assertEquals(pceGraph.calcPath(), true);
+        Assert.assertEquals(Optional.ofNullable(pceGraph.getPathAtoZ().get(2).getLatency()),
+            Optional.ofNullable(1.0));
+        Assert.assertEquals(pceGraph.getReturnStructure().getRate(), 100);
     }
 
     @Test(expected = Exception.class)
@@ -129,24 +402,22 @@ public class PceGraphTest {
 
     private PceGraph getOtnPceGraph(String type) {
         // Build Link
-        link = NodeUtils.createRoadmToRoadm("optical",
-                "optical2",
-                "DEG1-TTP-TX", "DEG1-TTP-RX").build();
-
+        link1 = NodeUtils.createRoadmToRoadm("optical",
+            "optical2",
+            "DEG1-TTP-TX", "DEG1-TTP-RX").build();
 
         node = NodeUtils.getOTNNodeBuilder(NodeUtils.geSupportingNodes(), OpenroadmTpType.XPONDERNETWORK).build();
 
-        PceOtnNode  pceOtnNode = new PceOtnNode(node, OpenroadmNodeType.MUXPDR,
-                new NodeId("optical"), ServiceFormat.OTU.getName(), "serviceType", null);
+        PceOtnNode pceOtnNode = new PceOtnNode(node, OpenroadmNodeType.MUXPDR,
+            new NodeId("optical"), ServiceFormat.OTU.getName(), "serviceType", null);
         pceOtnNode.validateXponder("optical", "sl");
         pceOtnNode.validateXponder("not optical", "sl");
         pceOtnNode.initXndrTps("AZ");
         pceOtnNode.checkAvailableTribPort();
         pceOtnNode.checkAvailableTribSlot();
 
-
         PceOtnNode pceOtnNode2 = new PceOtnNode(node, OpenroadmNodeType.MUXPDR,
-                new NodeId("optical2"), ServiceFormat.OTU.getName(), "serviceType", null);
+            new NodeId("optical2"), ServiceFormat.OTU.getName(), "serviceType", null);
         pceOtnNode2.validateXponder("optical", "sl");
         pceOtnNode2.validateXponder("not optical", "sl");
         pceOtnNode2.initXndrTps("AZ");
@@ -154,24 +425,226 @@ public class PceGraphTest {
         pceOtnNode2.checkAvailableTribPort();
         pceOtnNode2.checkAvailableTribSlot();
 
-        pceLink = new PceLink(link, pceOtnNode, pceOtnNode2);
-        pceLink.setClient("XPONDER-CLIENT");
+        pceLink1 = new PceLink(link1, pceOtnNode, pceOtnNode2);
+        pceLink1.setClient("XPONDER-CLIENT");
 
-        pceLink.getDestId();
-        pceOtnNode.addOutgoingLink(pceLink);
+        pceLink1.getDestId();
+        pceOtnNode.addOutgoingLink(pceLink1);
 
         // init PceHardContraints
         pceHardConstraints = new PceConstraints();
         // pceHardConstraints.setp
         allPceNodes = Map.of(new NodeId("optical"), pceOtnNode,
-                new NodeId("optical2"), pceOtnNode2);
+            new NodeId("optical2"), pceOtnNode2);
         rc = new PceResult();
         PceGraph otnPceGraph = new PceGraph(pceOtnNode, pceOtnNode2, allPceNodes,
-                pceHardConstraints,
-                null, rc,
-                type);
+            allPceLinks, pceHardConstraints,
+            null, rc,
+            type, null);
 
         return otnPceGraph;
     }
-}
 
+    private void saveOpenRoadmNetwork(Network network, String networkId)
+            throws InterruptedException, ExecutionException {
+        InstanceIdentifier<Network> nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class)
+            .child(Network.class, new NetworkKey(new NetworkId(networkId))).build();
+        WriteTransaction dataWriteTransaction = dataBroker.newWriteOnlyTransaction();
+        dataWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, nwInstanceIdentifier, network);
+        dataWriteTransaction.commit().get();
+    }
+
+    public static Node createNetworkNode(String nodeId, OpenroadmNodeType nodeType) {
+
+        Node1Builder node1Bldr = new Node1Builder()
+            .setOpenroadmVersion(OpenroadmVersionType._221);
+        var node2Bldr = new org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Node1Builder()
+            .setNodeType(nodeType);
+        SupportingNode supportingNode = new SupportingNodeBuilder()
+            .setNetworkRef(new NetworkId(NetworkUtils.CLLI_NETWORK_ID))
+            .setNodeRef(new NodeId("node1"))
+            .withKey(new SupportingNodeKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID),
+                new NodeId("node1")))
+            .build();
+
+        return new NodeBuilder()
+            .setNodeId(new NodeId(nodeId))
+            .withKey(new NodeKey(new NodeId(nodeId)))
+            .setSupportingNode(ImmutableMap.of(supportingNode.key(), supportingNode))
+            .addAugmentation(node1Bldr.build())
+            .addAugmentation(node2Bldr.build())
+            .build();
+    }
+
+    public static TerminationPoint createNetworkTp(String nodeId, String tpId) {
+        var nwTpId = new TpId(tpId);
+        return new TerminationPointBuilder()
+            .setTpId(nwTpId)
+            .withKey(new TerminationPointKey(nwTpId))
+            .addAugmentation(new TerminationPoint1Builder()
+                .setXpdrNetworkAttributes(new XpdrNetworkAttributesBuilder().setState(State.InService).build())
+                .build())
+            .build();
+    }
+
+    public static Node createTopologyNode(String nodeId, OpenroadmNodeType nodeType) {
+
+        var node1Bldr = new org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.Node1Builder()
+            .setXpdrAttributes(null);
+        var node2Bldr = new org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Node1Builder()
+            .setNodeType(nodeType);
+        SupportingNode supportingNode = new SupportingNodeBuilder()
+            .setNetworkRef(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))
+            .setNodeRef(new NodeId("node1"))
+            .withKey(new SupportingNodeKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID),
+                new NodeId("node1")))
+            .build();
+
+        return new NodeBuilder()
+            .setNodeId(new NodeId(nodeId))
+            .withKey(new NodeKey(new NodeId(nodeId)))
+            .setSupportingNode(ImmutableMap.of(supportingNode.key(), supportingNode))
+            .addAugmentation(node1Bldr.build())
+            .addAugmentation(node2Bldr.build())
+            .build();
+    }
+
+    public static PathComputationRequestInput getPCE1Request(Uint32 rate, ServiceFormat serviceFormat, String aaNodeId,
+                String aaClliId, String aaPortName, String zzNodeId, String zzClliId, String zzPortName) {
+
+        return new PathComputationRequestInputBuilder()
+            .setServiceName("service1")
+            .setResourceReserve(true)
+            .setPceRoutingMetric(PceMetric.HopCount)
+            .setServiceHandlerHeader(new ServiceHandlerHeaderBuilder()
+                .setRequestId("request1")
+                .build())
+            .setServiceAEnd(new ServiceAEndBuilder()
+                .setServiceFormat(serviceFormat)
+                .setServiceRate(Uint32.valueOf(100))
+                .setClli(aaClliId)
+                .setNodeId(aaNodeId)
+                .setTxDirection(new TxDirectionBuilder()
+                    .setPort(new PortBuilder()
+                        .setPortDeviceName(aaNodeId)
+                        .setPortType("fixed")
+                        .setPortName(aaPortName)
+                        .setPortRack("Some port-rack")
+                        .setPortShelf("Some port-shelf")
+                        .setPortSlot("Some port-slot")
+                        .setPortSubSlot("Some port-sub-slot")
+                        .build())
+                    .build())
+                .setRxDirection(new RxDirectionBuilder()
+                    .setPort(new PortBuilder()
+                        .setPortDeviceName(aaNodeId)
+                        .setPortType("fixed")
+                        .setPortName(aaPortName)
+                        .setPortRack("Some port-rack")
+                        .setPortShelf("Some port-shelf")
+                        .setPortSlot("Some port-slot")
+                        .setPortSubSlot("Some port-sub-slot")
+                        .build())
+                    .build())
+                .build())
+            .setServiceZEnd(new ServiceZEndBuilder()
+                .setServiceFormat(serviceFormat)
+                .setServiceRate(Uint32.valueOf(0))
+                .setClli(zzClliId)
+                .setNodeId(zzNodeId)
+                .setTxDirection(new TxDirectionBuilder()
+                    .setPort(new PortBuilder()
+                        .setPortDeviceName(zzNodeId)
+                        .setPortType("fixed")
+                        .setPortName(zzPortName)
+                        .setPortRack("Some port-rack")
+                        .setPortShelf("Some port-shelf")
+                        .setPortSlot("Some port-slot")
+                        .setPortSubSlot("Some port-sub-slot")
+                        .build())
+                    .build())
+                .setRxDirection(new RxDirectionBuilder()
+                    .setPort(new PortBuilder()
+                        .setPortDeviceName(zzNodeId)
+                        .setPortType("fixed")
+                        .setPortName(zzPortName)
+                        .setPortRack("Some port-rack")
+                        .setPortShelf("Some port-shelf")
+                        .setPortSlot("Some port-slot")
+                        .setPortSubSlot("Some port-sub-slot")
+                        .build())
+                    .build())
+                .build())
+            .setHardConstraints(new HardConstraintsBuilder()
+                .setCustomerCode(Set.of("Some customer-code"))
+                .setCoRouting(new CoRoutingBuilder()
+                    .setServiceIdentifierList(Map.of(
+                        new org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev211210.constraints.co
+                                .routing.ServiceIdentifierListKey("Some existing-service"),
+                        new ServiceIdentifierListBuilder().setServiceIdentifier("Some existing-service").build()))
+                    .build())
+                .build())
+            .setSoftConstraints(new SoftConstraintsBuilder()
+                .setCustomerCode(Set.of("Some customer-code"))
+                .setCoRouting(new CoRoutingBuilder()
+                    .setServiceIdentifierList(Map.of(
+                        new org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev211210.constraints.co
+                                .routing.ServiceIdentifierListKey("Some existing-service"),
+                        new ServiceIdentifierListBuilder().setServiceIdentifier("Some existing-service").build()))
+                    .build())
+                .build())
+            .build();
+    }
+
+    public static PathComputationRequestInput getPCE2Request(Uint32 rate, ServiceFormat serviceFormat, String aaNodeId,
+        String aaClliId, String aaPortName, String zzNodeId, String zzClliId, String zzPortName) {
+
+        return new PathComputationRequestInputBuilder()
+            .setServiceName("service1")
+            .setResourceReserve(true)
+            .setPceRoutingMetric(PceMetric.HopCount)
+            .setServiceHandlerHeader(new ServiceHandlerHeaderBuilder()
+                .setRequestId("request1")
+                .build())
+            .setServiceAEnd(new ServiceAEndBuilder()
+                .setServiceFormat(serviceFormat)
+                .setServiceRate(Uint32.valueOf(100))
+                .setClli(aaClliId)
+                .setNodeId(aaNodeId)
+                .setTxDirection(new TxDirectionBuilder()
+                  .build())
+                .setRxDirection(new RxDirectionBuilder()
+                    .build())
+                .build())
+            .setServiceZEnd(new ServiceZEndBuilder()
+                .setServiceFormat(serviceFormat)
+                .setServiceRate(Uint32.valueOf(0))
+                .setClli(zzClliId)
+                .setNodeId(zzNodeId)
+                .setTxDirection(new TxDirectionBuilder()
+                    .build())
+                .setRxDirection(new RxDirectionBuilder()
+                    .build())
+                .build())
+            .setHardConstraints(new HardConstraintsBuilder()
+                .setCustomerCode(Set.of("Some customer-code"))
+                .setCoRouting(new CoRoutingBuilder()
+                    .setServiceIdentifierList(Map.of(
+                        new org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev211210.constraints.co
+                                .routing.ServiceIdentifierListKey("Some existing-service"),
+                        new ServiceIdentifierListBuilder().setServiceIdentifier("Some existing-service").build()))
+                    .build())
+                .build())
+            .setSoftConstraints(new SoftConstraintsBuilder()
+                .setCustomerCode(Set.of("Some customer-code"))
+                .setCoRouting(new CoRoutingBuilder()
+                    .setServiceIdentifierList(Map.of(
+                        new org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev211210.constraints.co
+                                .routing.ServiceIdentifierListKey("Some existing-service"),
+                        new ServiceIdentifierListBuilder().setServiceIdentifier("Some existing-service").build()))
+                    .build())
+                .build())
+                    .build();
+    }
+
+}
index 88e0496..0dec7fd 100644 (file)
@@ -8,6 +8,9 @@
 
 package org.opendaylight.transportpce.pce.networkanalyzer;
 
+import static org.junit.Assert.assertEquals;
+
+import java.math.RoundingMode;
 import java.util.HashMap;
 import java.util.Map;
 import org.junit.Assert;
@@ -20,6 +23,7 @@ import org.opendaylight.transportpce.common.StringConstants;
 import org.opendaylight.transportpce.common.fixedflex.GridConstant;
 import org.opendaylight.transportpce.common.mapping.PortMapping;
 import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.link.types.rev191129.FiberPmd;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.link.types.rev191129.RatioDB;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Link1Builder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.TerminationPoint1Builder;
@@ -57,12 +61,12 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.top
 import org.opendaylight.yangtools.yang.common.Decimal64;
 import org.opendaylight.yangtools.yang.common.Uint32;
 
-
 public class PceLinkTest extends AbstractTest {
 
     private static final String LINK_ID_FORMAT = "%1$s-%2$sto%3$s-%4$s";
     private PceLink pceLink = null;
     private String deviceNodeId = "device node";
+    private String deviceNodeId2 = "device node 2";
     private String serviceType = "100GE";
     @Mock
     private PortMapping portMapping;
@@ -75,74 +79,113 @@ public class PceLinkTest extends AbstractTest {
     @Test
     public void testBuildPceLinkRoadmToRoadm() {
         Link link = createRoadmToRoadm("srcNode",
-                "destNode",
-                "srcTp", "destTp").build();
+            "destNode",
+            "srcTp", "destTp").build();
         NodeBuilder node1Builder = getNodeBuilder(geSupportingNodes());
         Node node = node1Builder.setNodeId(new NodeId("test")).build();
-        PceOpticalNode pceOpticalNode = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
-                OpenroadmNodeType.SRG, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
-                GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
-        pceLink = new PceLink(link, pceOpticalNode, pceOpticalNode);
+        PceOpticalNode pceOpticalNode1 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        PceOpticalNode pceOpticalNode2 = new PceOpticalNode(deviceNodeId2, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        pceLink = new PceLink(link, pceOpticalNode1, pceOpticalNode2);
+    }
+
+    @Test
+    public void testBuildPceLinkRoadmToRoadmWithoutPMD() {
+        Link link = createRoadmToRoadmWithoutPMD("srcNode",
+            "destNode",
+            "srcTp", "destTp").build();
+        NodeBuilder node1Builder = getNodeBuilder(geSupportingNodes());
+        Node node = node1Builder.setNodeId(new NodeId("test")).build();
+        PceOpticalNode pceOpticalNode1 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        PceOpticalNode pceOpticalNode2 = new PceOpticalNode(deviceNodeId2, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        pceLink = new PceLink(link, pceOpticalNode1, pceOpticalNode2);
+        Assert.assertNotNull(MapUtils.getOmsAttributesSpan(link));
+        Assert.assertEquals(1, pceLink.getsrlgList().size());
+        assertEquals("Checking length loss", 20.0, pceLink.getspanLoss(), 0.005);
+        assertEquals("Checking length loss", 825.0, pceLink.getcd(), 0.005);
+        assertEquals("Checking PMDvalue of link", 4.0, pceLink.getpmd2(), 0.005);
     }
 
     @Test
     public void testBuildPceLinkRoadmToRoadmWithoutLinkLatency() {
         Link link = createRoadmToRoadmWithoutLinkLatency("srcNode",
-                "destNode",
-                "srcTp", "destTp").build();
+            "destNode",
+            "srcTp", "destTp").build();
 
         NodeBuilder node1Builder = getNodeBuilder(geSupportingNodes());
         Node node = node1Builder.setNodeId(new NodeId("test")).build();
-        PceOpticalNode pceOpticalNode = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
-                OpenroadmNodeType.SRG, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
-                GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
-        pceLink = new PceLink(link, pceOpticalNode, pceOpticalNode);
+        PceOpticalNode pceOpticalNode1 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        PceOpticalNode pceOpticalNode2 = new PceOpticalNode(deviceNodeId2, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        pceLink = new PceLink(link, pceOpticalNode1, pceOpticalNode2);
     }
 
     @Test
     public void testBuildPceLinkOTN() {
+        // TODO: Modify with OTN node not PceO=ticalNode
         Link link = createOTNLink("srcNode",
-                "destNode",
-                "srcTp", "destTp").build();
+            "destNode",
+            "srcTp", "destTp").build();
 
         NodeBuilder node1Builder = getNodeBuilder(geSupportingNodes());
         Node node = node1Builder.setNodeId(new NodeId("test")).build();
-        PceOpticalNode pceOpticalNode = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
-                OpenroadmNodeType.SRG, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
-                GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
-        pceLink = new PceLink(link, pceOpticalNode, pceOpticalNode);
+        PceOpticalNode pceOpticalNode1 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.SWITCH, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        PceOpticalNode pceOpticalNode2 = new PceOpticalNode(deviceNodeId2, serviceType, portMapping, node,
+            OpenroadmNodeType.SWITCH, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        pceLink = new PceLink(link, pceOpticalNode1, pceOpticalNode2);
     }
 
     @Test
     public void testBuildPceLinkExponder() {
         Link link = createXponderLink("srcNode",
-                "destNode",
-                "srcTp", "destTp").build();
+            "destNode",
+            "srcTp", "destTp").build();
 
         NodeBuilder node1Builder = getNodeBuilder(geSupportingNodes());
         Node node = node1Builder.setNodeId(new NodeId("test")).build();
-        PceOpticalNode pceOpticalNode = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
-                OpenroadmNodeType.SRG, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
-                GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
-        pceLink = new PceLink(link, pceOpticalNode, pceOpticalNode);
+        PceOpticalNode pceOpticalNode1 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.XPONDER, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        PceOpticalNode pceOpticalNode2 = new PceOpticalNode(deviceNodeId2, serviceType, portMapping, node,
+            OpenroadmNodeType.SRG, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        pceLink = new PceLink(link, pceOpticalNode1, pceOpticalNode2);
     }
 
     @Test
     public void testCalcSpanOSNR() {
         Link link = createRoadmToRoadm("srcNode",
-                "destNode",
-                "srcTp", "destTp").build();
+            "destNode",
+            "srcTp", "destTp").build();
 
         NodeBuilder node1Builder = getNodeBuilder(geSupportingNodes());
         Node node = node1Builder.setNodeId(new NodeId("test")).build();
-        PceOpticalNode pceOpticalNode = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
-                OpenroadmNodeType.SRG, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
-                GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
-        pceLink = new PceLink(link, pceOpticalNode, pceOpticalNode);
+        PceOpticalNode pceOpticalNode1 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        PceOpticalNode pceOpticalNode2 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        pceLink = new PceLink(link, pceOpticalNode1, pceOpticalNode2);
         Assert.assertNotNull(MapUtils.getOmsAttributesSpan(link));
-        Assert.assertNotNull(pceLink.getosnr());
+        // Assert.assertNotNull(pceLink.getosnr());
         Assert.assertEquals(1, pceLink.getsrlgList().size());
-        Assert.assertTrue(7.857119000000001 == pceLink.getosnr());
+        assertEquals("Checking PMDvalue of link", 0.25, pceLink.getpmd2(), 0.005);
+        assertEquals("Checking CDvalue of link", 825, pceLink.getcd(), 0.005);
+        // Assert.assertTrue(7.857119000000001 == pceLink.getosnr());
         Assert.assertNull(pceLink.getOppositeLink());
         Assert.assertNull(pceLink.getOppositeLink());
         Assert.assertNotNull(pceLink.getDestTP());
@@ -162,126 +205,194 @@ public class PceLinkTest extends AbstractTest {
         Assert.assertNotNull(pceLink.getsourceCLLI());
         Assert.assertNotNull(pceLink.getdestCLLI());
         Assert.assertTrue(pceLink.toString().equals("PceLink type=" + pceLink.getlinkType()
-                + " ID=" + pceLink.getLinkId().getValue() + " latency=" + pceLink.getLatency().intValue()));
+            + " ID=" + pceLink.getLinkId().getValue() + " latency=" + pceLink.getLatency().intValue()));
+    }
+
+    @Test
+    public void testWrongSpanLoss() {
+        Link link = createInvalidRoadmToRoadm("srcNode",
+            "destNode",
+            "srcTp", "destTp").build();
+
+        NodeBuilder node1Builder = getNodeBuilder(geSupportingNodes());
+        Node node = node1Builder.setNodeId(new NodeId("test")).build();
+        PceOpticalNode pceOpticalNode1 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        PceOpticalNode pceOpticalNode2 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        pceLink = new PceLink(link, pceOpticalNode1, pceOpticalNode2);
+        Assert.assertNull(MapUtils.getOmsAttributesSpan(link));
+        Assert.assertNull(pceLink.getpmd2());
+        Assert.assertNull(pceLink.getpowerCorrection());
+        Assert.assertNull(pceLink.getcd());
+    }
+
+    @Test
+    public void testExtrapolatedPMD() {
+        Link link = createRoadmToRoadmWithoutPMD("srcNode",
+            "destNode",
+            "srcTp", "destTp").build();
+
+        NodeBuilder node1Builder = getNodeBuilder(geSupportingNodes());
+        Node node = node1Builder.setNodeId(new NodeId("test")).build();
+        PceOpticalNode pceOpticalNode1 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        PceOpticalNode pceOpticalNode2 = new PceOpticalNode(deviceNodeId, serviceType, portMapping, node,
+            OpenroadmNodeType.DEGREE, StringConstants.OPENROADM_DEVICE_VERSION_2_2_1,
+            GridConstant.SLOT_WIDTH_50, GridConstant.SLOT_WIDTH_50);
+        pceLink = new PceLink(link, pceOpticalNode1, pceOpticalNode2);
+        Assert.assertNotNull(MapUtils.getOmsAttributesSpan(link));
+        Assert.assertEquals(1, pceLink.getsrlgList().size());
+        assertEquals("Checking PMDvalue of link", 4.0, pceLink.getpmd2(), 0.005);
     }
 
     private static LinkBuilder createOTNLink(String srcNode, String destNode, String srcTp, String destTp) {
         Link1Builder link1Builder = new Link1Builder()
-                .setLinkType(OpenroadmLinkType.OTNLINK)
-                .setOperationalState(State.InService)
-                .setAdministrativeState(AdminStates.InService);
-        //create source link
-        return createLinkBuilder(srcNode, destNode, srcTp, destTp, link1Builder);
+            .setLinkType(OpenroadmLinkType.OTNLINK)
+            .setOperationalState(State.InService)
+            .setAdministrativeState(AdminStates.InService);
+        // create source link
+        return createLinkBuilder(false, false, 10000.0, srcNode, destNode, srcTp, destTp, link1Builder);
     }
 
     private static LinkBuilder createXponderLink(String srcNode, String destNode, String srcTp, String destTp) {
         Link1Builder link1Builder = new Link1Builder()
-                .setLinkType(OpenroadmLinkType.XPONDERINPUT)
-                .setAdministrativeState(AdminStates.InService)
-                .setOperationalState(State.InService);
-        //create source link
-        return createLinkBuilder(srcNode, destNode, srcTp, destTp, link1Builder);
+            .setLinkType(OpenroadmLinkType.XPONDERINPUT)
+            .setAdministrativeState(AdminStates.InService)
+            .setOperationalState(State.InService);
+        // create source link
+        return createLinkBuilder(false, false, 10.0, srcNode, destNode, srcTp, destTp, link1Builder);
     }
 
-    private static LinkBuilder createLinkBuilder(
+    private static LinkBuilder createLinkBuilder(boolean pmdpresent, boolean omspresent, double length,
             String srcNode, String destNode, String srcTp, String destTp, Link1Builder link1Builder) {
-        SourceBuilder ietfSrcLinkBldr =
-                new SourceBuilder().setSourceNode(new NodeId(srcNode)).setSourceTp(new TpId(srcTp));
-        //create destination link
-        DestinationBuilder ietfDestLinkBldr =
-                new DestinationBuilder().setDestNode(new NodeId(destNode))
-                        .setDestTp(new TpId(destTp));
+        SourceBuilder ietfSrcLinkBldr = new SourceBuilder().setSourceNode(new NodeId(srcNode))
+            .setSourceTp(new TpId(srcTp));
+        // create destination link
+        DestinationBuilder ietfDestLinkBldr = new DestinationBuilder().setDestNode(new NodeId(destNode))
+            .setDestTp(new TpId(destTp));
         LinkId linkId = new LinkId(String.format(LINK_ID_FORMAT, srcNode, srcTp, destNode, destTp));
 
-        //For setting up attributes for openRoadm augment
+        // For setting up attributes for openRoadm augment
         LinkConcatenation linkConcatenation = new LinkConcatenationBuilder()
+            .withKey(new LinkConcatenationKey(Uint32.valueOf(1)))
+            .setSRLGLength(Decimal64.valueOf(length, RoundingMode.FLOOR))
+            .addAugmentation(new LinkConcatenation1Builder()
+                .setFiberType(FiberType.Smf)
+                .build())
+            .build();
+        if (pmdpresent) {
+            linkConcatenation = new LinkConcatenationBuilder()
                 .withKey(new LinkConcatenationKey(Uint32.valueOf(1)))
-                .setSRLGLength(Decimal64.valueOf("20"))
+                .setSRLGLength(Decimal64.valueOf(length, RoundingMode.FLOOR))
                 .addAugmentation(new LinkConcatenation1Builder()
-                    .setFiberType(FiberType.Dsf)
+                    .setFiberType(FiberType.Smf)
+                    .setPmd(FiberPmd.getDefaultInstance("0.500"))
                     .build())
                 .build();
-        OMSAttributesBuilder omsAttributesBuilder =
-                new OMSAttributesBuilder()
-                        .setSpan(new SpanBuilder()
-                                .setSpanlossCurrent(new RatioDB(Decimal64.valueOf("55")))
-                                .setLinkConcatenation(Map.of(linkConcatenation.key(),
-                                        linkConcatenation
-                                )).build());
-
+        }
+        OMSAttributesBuilder omsAttributesBuilder = new OMSAttributesBuilder()
+            .setSpan(new SpanBuilder()
+                // .setSpanlossCurrent(new RatioDB(Decimal64.valueOf("55")))
+                .setSpanlossCurrent(new RatioDB(Decimal64.valueOf("20")))
+                .setLinkConcatenation(Map.of(linkConcatenation.key(), linkConcatenation))
+                .build());
 
         LinkBuilder linkBuilder = new LinkBuilder()
-                .setSource(ietfSrcLinkBldr.build())
-                .setDestination(ietfDestLinkBldr.build())
-                .setLinkId(linkId)
-                .withKey(new LinkKey(linkId));
+            .setSource(ietfSrcLinkBldr.build())
+            .setDestination(ietfDestLinkBldr.build())
+            .setLinkId(linkId)
+            .withKey(new LinkKey(linkId));
 
         linkBuilder.addAugmentation(link1Builder.build());
+        if (omspresent) {
+            var linkBuilderNetworkLink = new org.opendaylight.yang.gen.v1.http
+                .org.openroadm.network.topology.rev211210.Link1Builder()
+                    .setOMSAttributes(omsAttributesBuilder
+                    .build());
 
-        org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.Link1Builder linkBuilderNetworkLink
-                = new org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.Link1Builder()
-                .setOMSAttributes(omsAttributesBuilder
-                        .build());
-
-        linkBuilder.addAugmentation(linkBuilderNetworkLink.build());
+            linkBuilder.addAugmentation(linkBuilderNetworkLink.build());
+        }
         return linkBuilder;
     }
 
     private static LinkBuilder createRoadmToRoadm(String srcNode, String destNode, String srcTp, String destTp) {
-        Link1Builder link1Builder = new Link1Builder()
+        return createLinkBuilder(true, true, 50000.0, srcNode, destNode, srcTp, destTp, new Link1Builder()
+                .setLinkLatency(Uint32.valueOf(100))
+                .setAdministrativeState(AdminStates.InService)
+                .setOperationalState(State.InService)
+                .setLinkType(OpenroadmLinkType.ROADMTOROADM)
+                .setLinkLength(Decimal64.valueOf(50.0, RoundingMode.FLOOR)));
+    }
+
+    private static LinkBuilder createRoadmToRoadmWithoutPMD(String srcNode, String destNode, String srcTp,
+            String destTp) {
+        return createLinkBuilder(false, true, 50000.0, srcNode, destNode, srcTp, destTp, new Link1Builder()
+                .setLinkLatency(Uint32.valueOf(100))
+                .setAdministrativeState(AdminStates.InService)
+                .setOperationalState(State.InService)
+                .setLinkType(OpenroadmLinkType.ROADMTOROADM)
+                .setLinkLength(Decimal64.valueOf(50.0, RoundingMode.FLOOR)));
+    }
+
+    private static LinkBuilder createInvalidRoadmToRoadm(String srcNode, String destNode,
+            String srcTp, String destTp) {
+        return createLinkBuilder(false, false, 0.0, srcNode, destNode, srcTp, destTp, new Link1Builder()
                 .setLinkLatency(Uint32.valueOf(100))
                 .setAdministrativeState(AdminStates.InService)
                 .setOperationalState(State.InService)
-                .setLinkType(OpenroadmLinkType.ROADMTOROADM);
-        return createLinkBuilder(srcNode, destNode, srcTp, destTp, link1Builder);
+                .setLinkType(OpenroadmLinkType.ROADMTOROADM));
     }
 
     private static LinkBuilder createRoadmToRoadmWithoutLinkLatency(
             String srcNode, String destNode, String srcTp, String destTp) {
-        Link1Builder link1Builder = new Link1Builder()
-                .setLinkType(OpenroadmLinkType.ROADMTOROADM);
-        return createLinkBuilder(srcNode, destNode, srcTp, destTp, link1Builder);
+        return createLinkBuilder(true, true, 50000.0, srcNode, destNode, srcTp, destTp, new Link1Builder()
+                .setLinkType(OpenroadmLinkType.ROADMTOROADM));
     }
 
-    private Map<SupportingNodeKey,SupportingNode> geSupportingNodes() {
-        Map<SupportingNodeKey,SupportingNode> supportingNodes1 = new HashMap<>();
+    private Map<SupportingNodeKey, SupportingNode> geSupportingNodes() {
+        Map<SupportingNodeKey, SupportingNode> supportingNodes1 = new HashMap<>();
         SupportingNode supportingNode1 = new SupportingNodeBuilder()
-                .setNodeRef(new NodeId("node 1"))
-                .setNetworkRef(new NetworkId(NetworkUtils.CLLI_NETWORK_ID))
-                .build();
+            .setNodeRef(new NodeId("node 1"))
+            .setNetworkRef(new NetworkId(NetworkUtils.CLLI_NETWORK_ID))
+            .build();
         supportingNodes1
-                .put(supportingNode1.key(),supportingNode1);
+            .put(supportingNode1.key(), supportingNode1);
 
         SupportingNode supportingNode2 = new SupportingNodeBuilder()
-                .setNodeRef(new NodeId("node 2"))
-                .setNetworkRef(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))
-                .build();
+            .setNodeRef(new NodeId("node 2"))
+            .setNetworkRef(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))
+            .build();
         supportingNodes1
-                .put(supportingNode2.key(),supportingNode2);
+            .put(supportingNode2.key(), supportingNode2);
         return supportingNodes1;
     }
 
-    private NodeBuilder getNodeBuilder(Map<SupportingNodeKey,SupportingNode> supportingNodes1) {
-        //update tp of nodes
+    private NodeBuilder getNodeBuilder(Map<SupportingNodeKey, SupportingNode> supportingNodes1) {
+        // update tp of nodes
         TerminationPointBuilder xpdrTpBldr = new TerminationPointBuilder()
-                .withKey(new TerminationPointKey(new TpId("xpdr")));
+            .withKey(new TerminationPointKey(new TpId("xpdr")));
         TerminationPoint1Builder tp1Bldr = new TerminationPoint1Builder();
 
         tp1Bldr.setTpType(OpenroadmTpType.XPONDERNETWORK).setAdministrativeState(AdminStates.InService)
-                .setOperationalState(State.InService);
+            .setOperationalState(State.InService);
         xpdrTpBldr.addAugmentation(tp1Bldr.build());
         TerminationPoint xpdr = xpdrTpBldr.build();
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1 node1 =
-            new Node1Builder().setTerminationPoint(Map.of(xpdr.key(),xpdr)).build();
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226
+            .Node1 node1 = new Node1Builder()
+                .setTerminationPoint(Map.of(xpdr.key(), xpdr)).build();
         org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Node1 node11 =
             new org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Node1Builder()
                 .setOperationalState(State.InService).setAdministrativeState(AdminStates.InService).build();
         return new NodeBuilder()
-                .setNodeId(new NodeId("node 1"))
-                .withKey(new NodeKey(new NodeId("node 1")))
-                .addAugmentation(node1)
-                .addAugmentation(node11)
-                .setSupportingNode(supportingNodes1);
+            .setNodeId(new NodeId("node 1"))
+            .withKey(new NodeKey(new NodeId("node 1")))
+            .addAugmentation(node1)
+            .addAugmentation(node11)
+            .setSupportingNode(supportingNodes1);
     }
 
 }
index e525df3..0e081ea 100644 (file)
@@ -8,17 +8,21 @@
 
 package org.opendaylight.transportpce.pce.utils;
 
+import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.opendaylight.transportpce.common.NetworkUtils;
 import org.opendaylight.transportpce.common.fixedflex.GridUtils;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.link.types.rev191129.RatioDB;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Link1Builder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Node1;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.TerminationPoint1Builder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev211210.span.attributes.LinkConcatenation1.FiberType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev211210.span.attributes.LinkConcatenation1Builder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.link.OMSAttributesBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.link.oms.attributes.SpanBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.DegreeAttributes;
@@ -35,6 +39,9 @@ import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev21121
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.node.termination.point.XpdrPortAttributesBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmLinkType;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmTpType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.link.concatenation.LinkConcatenation;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.link.concatenation.LinkConcatenationBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.link.concatenation.LinkConcatenationKey;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.xpdr.tp.supported.interfaces.SupportedInterfaceCapability;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.xpdr.tp.supported.interfaces.SupportedInterfaceCapabilityBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.xpdr.tp.supported.interfaces.SupportedInterfaceCapabilityKey;
@@ -64,13 +71,14 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.top
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointKey;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.common.Decimal64;
 import org.opendaylight.yangtools.yang.common.Uint32;
 
 public final class NodeUtils {
 
     private static final String LINK_ID_FORMAT = "%1$s-%2$sto%3$s-%4$s";
 
-    public static LinkBuilder createLinkBuilder(
+    public static LinkBuilder createLinkBuilder(boolean omsPresent,
             String srcNode, String destNode, String srcTp, String destTp, Link1Builder link1Builder) {
         SourceBuilder ietfSrcLinkBldr =
                 new SourceBuilder().setSourceNode(new NodeId(srcNode)).setSourceTp(new TpId(srcTp));
@@ -79,15 +87,34 @@ public final class NodeUtils {
                 new DestinationBuilder().setDestNode(new NodeId(destNode)).setDestTp(new TpId(destTp));
         LinkId linkId = new LinkId(String.format(LINK_ID_FORMAT, srcNode, srcTp, destNode, destTp));
 
-        LinkId oppositeLinkId = new LinkId("OpenROADM-3-2-DEG1-to-OpenROADM-3-1-DEG1");
-        // Augementation
+        LinkId oppositeLinkId = new LinkId(String.format(LINK_ID_FORMAT, destNode, destTp, srcNode, srcTp));
+        // Augmentations
+        LinkConcatenation linkConcatenation = new LinkConcatenationBuilder()
+            .withKey(new LinkConcatenationKey(Uint32.valueOf(1)))
+            .setSRLGLength(Decimal64.valueOf(50000, RoundingMode.FLOOR))
+            .addAugmentation(new LinkConcatenation1Builder()
+                .setFiberType(FiberType.Smf)
+                .build())
+            .build();
+        OMSAttributesBuilder omsAttributesBuilder = new OMSAttributesBuilder()
+            .setSpan(new SpanBuilder()
+                .setSpanlossCurrent(new RatioDB(Decimal64.valueOf("20")))
+                .setLinkConcatenation(Map.of(linkConcatenation.key(), linkConcatenation))
+                .build());
+
         Augmentation<Link> aug11 = new org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210
                 .Link1Builder()
-                .setAmplified(true)
-                .setOMSAttributes(new OMSAttributesBuilder()
-                        .setSpan(new SpanBuilder().build())
-                        .build())
+                .setAmplified(false)
+                .setOMSAttributes(omsAttributesBuilder.build())
                 .build();
+        if (!omsPresent) {
+            return new LinkBuilder()
+                .setSource(ietfSrcLinkBldr.build())
+                .setDestination(ietfDestLinkBldr.build())
+                .setLinkId(linkId)
+                .withKey(new LinkKey(linkId))
+                .addAugmentation(link1Builder.setOppositeLink(oppositeLinkId).build());
+        }
         return new LinkBuilder()
                 .setSource(ietfSrcLinkBldr.build())
                 .setDestination(ietfDestLinkBldr.build())
@@ -99,12 +126,48 @@ public final class NodeUtils {
 
     public static LinkBuilder createRoadmToRoadm(String srcNode, String destNode, String srcTp, String destTp) {
         Link1Builder link1Builder = new Link1Builder()
-                .setLinkLatency(Uint32.valueOf(30))
+                .setLinkLatency(Uint32.valueOf(2))
+                .setLinkLength(Decimal64.valueOf("50.0"))
                 .setLinkType(OpenroadmLinkType.ROADMTOROADM)
                 .setAdministrativeState(AdminStates.InService)
                 .setOperationalState(State.InService);
-        return createLinkBuilder(srcNode, destNode, srcTp, destTp, link1Builder);
+        return createLinkBuilder(true, srcNode, destNode, srcTp, destTp, link1Builder);
+    }
+
+    public static LinkBuilder createAdd(String srcNode, String destNode, String srcTp, String destTp) {
+        return createLinkBuilder(false, srcNode, destNode, srcTp, destTp, new Link1Builder()
+               .setLinkLatency(Uint32.valueOf(0))
+               .setLinkLength(Decimal64.valueOf("0.01"))
+               .setLinkType(OpenroadmLinkType.ADDLINK)
+               .setAdministrativeState(AdminStates.InService)
+               .setOperationalState(State.InService));
+    }
+
+    public static LinkBuilder createDrop(String srcNode, String destNode, String srcTp, String destTp) {
+        return createLinkBuilder(false, srcNode, destNode, srcTp, destTp, new Link1Builder()
+                .setLinkLatency(Uint32.valueOf(0))
+                .setLinkLength(Decimal64.valueOf("0.01"))
+                .setLinkType(OpenroadmLinkType.DROPLINK)
+                .setAdministrativeState(AdminStates.InService)
+                .setOperationalState(State.InService));
+    }
 
+    public static LinkBuilder createXpdrToSrg(String srcNode, String destNode, String srcTp, String destTp) {
+        return createLinkBuilder(false, srcNode, destNode, srcTp, destTp, new Link1Builder()
+                .setLinkLatency(Uint32.valueOf(0))
+                .setLinkLength(Decimal64.valueOf("0.01"))
+                .setLinkType(OpenroadmLinkType.XPONDEROUTPUT)
+                .setAdministrativeState(AdminStates.InService)
+                .setOperationalState(State.InService));
+    }
+
+    public static LinkBuilder createSrgToXpdr(String srcNode, String destNode, String srcTp, String destTp) {
+        return createLinkBuilder(false, srcNode, destNode, srcTp, destTp, new Link1Builder()
+                .setLinkLatency(Uint32.valueOf(0))
+                .setLinkLength(Decimal64.valueOf("0.01"))
+                .setLinkType(OpenroadmLinkType.XPONDERINPUT)
+                .setAdministrativeState(AdminStates.InService)
+                .setOperationalState(State.InService));
     }
 
     public static Map<SupportingNodeKey, SupportingNode> geSupportingNodes() {
@@ -129,31 +192,113 @@ public final class NodeUtils {
 
 
         //update tp of nodes
-        TerminationPointBuilder xpdrTpBldr = new TerminationPointBuilder()
-                .withKey(new TerminationPointKey(new TpId("xpdr")));
+        TerminationPointBuilder xpdrNwTpBldr = new TerminationPointBuilder()
+                .withKey(new TerminationPointKey(new TpId("xpdrNWTXRX")));
         TerminationPoint1Builder tp1Bldr = new TerminationPoint1Builder();
-        org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.TerminationPoint1Builder tp11Bldr =
+        var tp11Bldr =
             new org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.TerminationPoint1Builder()
                 .setAdministrativeState(AdminStates.InService)
                 .setOperationalState(State.InService);
-
         tp1Bldr.setTpType(OpenroadmTpType.XPONDERNETWORK);
-        xpdrTpBldr.addAugmentation(tp1Bldr.build());
-        xpdrTpBldr.addAugmentation(tp11Bldr.build());
-        TerminationPoint xpdr = xpdrTpBldr.build();
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1 node1 =
-            new Node1Builder().setTerminationPoint(Map.of(xpdr.key(),xpdr)).build();
+        xpdrNwTpBldr.addAugmentation(tp1Bldr.build());
+        xpdrNwTpBldr.addAugmentation(tp11Bldr.build());
+        xpdrNwTpBldr.addAugmentation(
+                new org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210
+                .TerminationPoint1Builder()
+            .setXpdrNetworkAttributes(new XpdrNetworkAttributesBuilder()
+                .setState(State.InService).build())
+                .build());
+
+        TerminationPointBuilder xpdrClientTpBldr = new TerminationPointBuilder()
+            .withKey(new TerminationPointKey(new TpId("xpdrClientTXRX")));
+        TerminationPoint1Builder tp2Bldr = new TerminationPoint1Builder();
+        var tp21Bldr =
+            new org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.TerminationPoint1Builder()
+            .setAdministrativeState(AdminStates.InService)
+            .setOperationalState(State.InService);
+        tp2Bldr.setTpType(OpenroadmTpType.XPONDERCLIENT);
+        xpdrClientTpBldr.addAugmentation(tp2Bldr.build());
+        xpdrClientTpBldr.addAugmentation(tp21Bldr.build());
+        TerminationPoint xpdrClient = xpdrClientTpBldr.build();
+        TerminationPoint xpdrNw = xpdrNwTpBldr.build();
+
+        var node1 =
+            new Node1Builder().setTerminationPoint(Map.of(xpdrNw.key(),xpdrNw, xpdrClient.key(), xpdrClient)).build();
         Node1 node11 = new org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Node1Builder()
             .setAdministrativeState(AdminStates.InService)
             .setOperationalState(State.InService).build();
         return new NodeBuilder()
-                .setNodeId(new NodeId("node 1"))
-                .withKey(new NodeKey(new NodeId("node 1")))
+                .setNodeId(new NodeId("XPDR1"))
+                .withKey(new NodeKey(new NodeId("XPDR1")))
                 .addAugmentation(node1)
                 .addAugmentation(node11)
                 .setSupportingNode(supportingNodes1);
     }
 
+    public static NodeBuilder getDegNodeBuilder(Map<SupportingNodeKey, SupportingNode> supportingNodes, String nodeId) {
+        // update tp of nodes
+        TerminationPoint degTTP = new TerminationPointBuilder()
+            .withKey(new TerminationPointKey(new TpId("DEG1-TTP-TXRX")))
+            .addAugmentation(
+                new TerminationPoint1Builder()
+                .setTpType(OpenroadmTpType.DEGREETXRXTTP)
+                .setAdministrativeState(AdminStates.InService)
+                .setOperationalState(State.InService)
+                .build())
+            .build();
+        TerminationPoint degCTP = new TerminationPointBuilder()
+            .withKey(new TerminationPointKey(new TpId("DEG1-CTP-TXRX")))
+            .addAugmentation(
+                new TerminationPoint1Builder()
+                    .setTpType(OpenroadmTpType.DEGREETXRXCTP)
+                    .setAdministrativeState(AdminStates.InService)
+                    .setOperationalState(State.InService)
+                    .build())
+            .build();
+        return new NodeBuilder()
+            .setNodeId(new NodeId(nodeId))
+            .withKey(new NodeKey(new NodeId(nodeId)))
+            .addAugmentation(
+                new Node1Builder()
+                    .setTerminationPoint(Map.of(degTTP.key(), degTTP, degCTP.key(), degCTP))
+                .build())
+            .addAugmentation(
+                new org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Node1Builder()
+                    .setOperationalState(State.InService).setAdministrativeState(AdminStates.InService).build())
+            .setSupportingNode(supportingNodes);
+    }
+
+    public static NodeBuilder getSrgNodeBuilder(Map<SupportingNodeKey, SupportingNode> supportingNodes, String nodeId) {
+        // update tp of nodes
+        TerminationPoint srgPP = new TerminationPointBuilder()
+            .withKey(new TerminationPointKey(new TpId("SRG1-PP-TXRX")))
+            .addAugmentation(
+                new TerminationPoint1Builder()
+                    .setTpType(OpenroadmTpType.SRGTXRXPP)
+                    .setAdministrativeState(AdminStates.InService)
+                    .setOperationalState(State.InService)
+                    .build())
+            .build();
+        TerminationPoint srgCP = new TerminationPointBuilder()
+            .withKey(new TerminationPointKey(new TpId("SRG1-CP-TXRX")))
+            .addAugmentation(
+                new TerminationPoint1Builder()
+                    .setTpType(OpenroadmTpType.SRGTXRXCP)
+                    .setAdministrativeState(AdminStates.InService)
+                    .setOperationalState(State.InService)
+                    .build())
+            .build();
+        return new NodeBuilder()
+            .setNodeId(new NodeId(nodeId))
+            .withKey(new NodeKey(new NodeId(nodeId)))
+            .addAugmentation(
+                new Node1Builder()
+                    .setTerminationPoint(Map.of(srgPP.key(), srgPP, srgCP.key(), srgCP)).build())
+            .addAugmentation(
+                new org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Node1Builder()
+                    .setOperationalState(State.InService).setAdministrativeState(AdminStates.InService).build())
+            .setSupportingNode(supportingNodes);
+    }
 
     // OTN network node
     public static List<SupportingNode> getOTNSupportingNodes() {
diff --git a/pce/src/test/resources/apidocCatalog10_1OptSpecV5_1.json b/pce/src/test/resources/apidocCatalog10_1OptSpecV5_1.json
new file mode 100644 (file)
index 0000000..413c6f5
--- /dev/null
@@ -0,0 +1,662 @@
+{
+    "operational-mode-catalog": {
+        "openroadm-operational-modes": {
+            "grid-parameters": {
+                "min-central-frequency": "191.32500000",
+                "max-central-frequency": "196.12500000",
+                "central-frequency-granularity": "12.50000",
+                "min-spacing": "37.50000"
+            },
+            "xponders-pluggables": {
+                "xponder-pluggable-openroadm-operational-mode": [
+                    {
+                        "openroadm-operational-mode-id": "OR-W-100G-SC",
+                        "baud-rate": "28.0",
+                        "line-rate": "111.8",
+                        "modulation-format": "dp-qpsk",
+                        "min-TX-osnr": "33.000",
+                        "TX-OOB-osnr": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-OOB-osnr-multi-channel-value": "31.000",
+                            "min-OOB-osnr-single-channel-value": "43.000"
+                        },
+                        "output-power-range": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-output-power": "-5.000",
+                            "max-output-power": "0.000"
+                        },
+                        "min-RX-osnr-tolerance": "17.000",
+                        "min-input-power-at-RX-osnr": "-22.000",
+                        "max-input-power": "1.000",
+                        "channel-width": "40.00000",
+                        "fec-type": "org-openroadm-common-types:scfec",
+                        "penalties": [
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "18000",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "6",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "30",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-22",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "cross-talk-total-power-dB",
+                                "up-to-boundary": "15",
+                                "penalty-value": "0.200"
+                            },
+                            {
+                                "parameter-and-unit": "colorless-drop-adjacent-channel-crosstalk-GHz",
+                                "up-to-boundary": "4",
+                                "penalty-value": "0.200"
+                            }
+                        ]
+                    },
+                    {
+                        "openroadm-operational-mode-id": "OR-W-100G-oFEC-31.6Gbd",
+                        "baud-rate": "31.6",
+                        "line-rate": "126.3",
+                        "modulation-format": "dp-qpsk",
+                        "min-TX-osnr": "37.000",
+                        "TX-OOB-osnr": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-OOB-osnr-multi-channel-value": "36.000"
+                        },
+                        "output-power-range": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-output-power": "-5.000",
+                            "max-output-power": "0.000"
+                        },
+                        "min-RX-osnr-tolerance": "12.000",
+                        "min-input-power-at-RX-osnr": "-18.000",
+                        "max-input-power": "1.000",
+                        "channel-width": "37.88400",
+                        "fec-type": "org-openroadm-common-types:ofec",
+                        "min-roll-off": "0.05",
+                        "max-roll-off": "0.20",
+                        "penalties": [
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "4000",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "48000",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "1",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "2",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "4",
+                                "penalty-value": "2.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "6",
+                                "penalty-value": "4.000"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "10",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "30",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-18",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-20",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "cross-talk-total-power-dB",
+                                "up-to-boundary": "15",
+                                "penalty-value": "0.200"
+                            },
+                            {
+                                "parameter-and-unit": "colorless-drop-adjacent-channel-crosstalk-GHz",
+                                "up-to-boundary": "4",
+                                "penalty-value": "0.200"
+                            }
+                        ]
+                    },
+                    {
+                        "openroadm-operational-mode-id": "OR-W-200G-oFEC-31.6Gbd",
+                        "baud-rate": "31.6",
+                        "line-rate": "252.6",
+                        "modulation-format": "dp-qam16",
+                        "min-TX-osnr": "37.000",
+                        "TX-OOB-osnr": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-OOB-osnr-multi-channel-value": "36.000"
+                        },
+                        "output-power-range": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-output-power": "-5.000",
+                            "max-output-power": "0.000"
+                        },
+                        "min-RX-osnr-tolerance": "20.500",
+                        "min-input-power-at-RX-osnr": "-16.000",
+                        "max-input-power": "1.000",
+                        "channel-width": "37.88400",
+                        "fec-type": "org-openroadm-common-types:ofec",
+                        "min-roll-off": "0.05",
+                        "max-roll-off": "0.20",
+                        "penalties": [
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "4000",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "24000",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "1",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "2",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "4",
+                                "penalty-value": "2.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "6",
+                                "penalty-value": "4.000"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "10",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "30",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-16",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-18",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-20",
+                                "penalty-value": "2.000"
+                            },
+                            {
+                                "parameter-and-unit": "cross-talk-total-power-dB",
+                                "up-to-boundary": "15",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "colorless-drop-adjacent-channel-crosstalk-GHz",
+                                "up-to-boundary": "4",
+                                "penalty-value": "0.500"
+                            }
+                        ]
+                    },
+                    {
+                        "openroadm-operational-mode-id": "OR-W-200G-oFEC-63.1Gbd",
+                        "baud-rate": "63.1",
+                        "line-rate": "252.6",
+                        "modulation-format": "dp-qpsk",
+                        "min-TX-osnr": "37.000",
+                        "TX-OOB-osnr": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-OOB-osnr-multi-channel-value": "36.000"
+                        },
+                        "output-power-range": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-output-power": "-5.000",
+                            "max-output-power": "0.000"
+                        },
+                        "min-RX-osnr-tolerance": "17.000",
+                        "min-input-power-at-RX-osnr": "-18.000",
+                        "max-input-power": "1.000",
+                        "channel-width": "75.72000",
+                        "fec-type": "org-openroadm-common-types:ofec",
+                        "min-roll-off": "0.05",
+                        "max-roll-off": "0.20",
+                        "penalties": [
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "4000",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "24000",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "1",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "2",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "4",
+                                "penalty-value": "2.500"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "10",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "25",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-18",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-20",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "cross-talk-total-power-dB",
+                                "up-to-boundary": "15",
+                                "penalty-value": "0.300"
+                            },
+                            {
+                                "parameter-and-unit": "colorless-drop-adjacent-channel-crosstalk-GHz",
+                                "up-to-boundary": "4",
+                                "penalty-value": "0.500"
+                            }
+                        ]
+                    },
+                    {
+                        "openroadm-operational-mode-id": "OR-W-300G-oFEC-63.1Gbd",
+                        "baud-rate": "63.1",
+                        "line-rate": "378.8",
+                        "modulation-format": "dp-qam16",
+                        "min-TX-osnr": "37.000",
+                        "TX-OOB-osnr": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-OOB-osnr-multi-channel-value": "36.000"
+                        },
+                        "output-power-range": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-output-power": "-5.000",
+                            "max-output-power": "0.000"
+                        },
+                        "min-RX-osnr-tolerance": "21.000",
+                        "min-input-power-at-RX-osnr": "-16.000",
+                        "max-input-power": "1.000",
+                        "channel-width": "75.72000",
+                        "fec-type": "org-openroadm-common-types:ofec",
+                        "min-roll-off": "0.05",
+                        "max-roll-off": "0.20",
+                        "penalties": [
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "4000",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "18000",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "1.00",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "2.00",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "4.00",
+                                "penalty-value": "2.500"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "10.00",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "25.00",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-16.00",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-18.00",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-20.00",
+                                "penalty-value": "2.000"
+                            },
+                            {
+                                "parameter-and-unit": "cross-talk-total-power-dB",
+                                "up-to-boundary": "15.00",
+                                "penalty-value": "0.300"
+                            },
+                            {
+                                "parameter-and-unit": "colorless-drop-adjacent-channel-crosstalk-GHz",
+                                "up-to-boundary": "4.0",
+                                "penalty-value": "0.500"
+                            }
+                        ]
+                    },
+                    {
+                        "openroadm-operational-mode-id": "OR-W-400G-oFEC-63.1Gbd",
+                        "baud-rate": "63.1",
+                        "line-rate": "505.1",
+                        "modulation-format": "dp-qam8",
+                        "min-TX-osnr": "37.000",
+                        "TX-OOB-osnr": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-OOB-osnr-multi-channel-value": "36.000"
+                        },
+                        "output-power-range": {
+                            "WR-openroadm-operational-mode-id": "MW-WR-core",
+                            "min-output-power": "-5.000",
+                            "max-output-power": "0.000"
+                        },
+                        "min-RX-osnr-tolerance": "24.000",
+                        "min-input-power-at-RX-osnr": "-14.000",
+                        "max-input-power": "1.000",
+                        "channel-width": "75.72000",
+                        "fec-type": "org-openroadm-common-types:ofec",
+                        "min-roll-off": "0.05",
+                        "max-roll-off": "0.20",
+                        "penalties": [
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "4000",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "CD-ps/nm",
+                                "up-to-boundary": "12000",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "1.00",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "2.00",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "PDL-dB",
+                                "up-to-boundary": "4.00",
+                                "penalty-value": "2.500"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "10.00",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "PMD-ps",
+                                "up-to-boundary": "20.00",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-14",
+                                "penalty-value": "0.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-16.00",
+                                "penalty-value": "1.000"
+                            },
+                            {
+                                "parameter-and-unit": "power-dBm",
+                                "up-to-boundary": "-18.00",
+                                "penalty-value": "2.000"
+                            },
+                            {
+                                "parameter-and-unit": "cross-talk-total-power-dB",
+                                "up-to-boundary": "13.00",
+                                "penalty-value": "0.300"
+                            },
+                            {
+                                "parameter-and-unit": "cross-talk-total-power-dB",
+                                "up-to-boundary": "15.00",
+                                "penalty-value": "0.500"
+                            },
+                            {
+                                "parameter-and-unit": "colorless-drop-adjacent-channel-crosstalk-GHz",
+                                "up-to-boundary": "4.10",
+                                "penalty-value": "0.500"
+                            }
+                        ]
+                    }
+                ]
+            },
+            "roadms": {
+                "Express": {
+                    "openroadm-operational-mode": {
+                        "openroadm-operational-mode-id": "MW-MW-core",
+                        "per-channel-Pin-min": "-21.000",
+                        "per-channel-Pin-max": "-9.000",
+                        "max-introduced-pdl": "1.500",
+                        "max-introduced-dgd": "3.00",
+                        "max-introduced-cd": "25.00",
+                        "osnr-polynomial-fit": {
+                            "A": "-0.00059520",
+                            "B": "-0.06250000",
+                            "C": "-1.07100000",
+                            "D": "27.99000000"
+                        },
+                        "mask-power-vs-pin": [
+                            {
+                                "lower-boundary": "0",
+                                "upper-boundary": "6",
+                                "C": "1.00000000",
+                                "D": "-9.00000000",
+                                "fiber-type": "smf"
+                            },
+                            {
+                                "lower-boundary": "6",
+                                "upper-boundary": "8",
+                                "C": "-0.00000000",
+                                "D": "-3.00000000",
+                                "fiber-type": "smf"
+                            },
+                            {
+                                "lower-boundary": "8",
+                                "upper-boundary": "23",
+                                "C": "0.33333334",
+                                "D": "-5.66666667",
+                                "fiber-type": "smf"
+                            },
+                            {
+                                "lower-boundary": "23",
+                                "upper-boundary": "27",
+                                "C": "0.00000000",
+                                "D": "2.00000000",
+                                "fiber-type": "smf"
+                            }
+                        ]
+                    }
+                },
+                "Add": {
+                    "add-openroadm-operational-mode": {
+                        "openroadm-operational-mode-id": "MW-WR-core",
+                        "incremental-osnr": "33.000",
+                        "per-channel-Pin-min": "-6.000",
+                        "per-channel-Pin-max": "3.000",
+                        "max-introduced-pdl": "1.500",
+                        "max-introduced-dgd": "3.00",
+                        "max-introduced-cd": "25.00",
+                        "mask-power-vs-pin": [
+                            {
+                                "lower-boundary": "0",
+                                "upper-boundary": "6",
+                                "C": "1.00000000",
+                                "D": "-9.00000000",
+                                "fiber-type": "smf"
+                            },
+                            {
+                                "lower-boundary": "6",
+                                "upper-boundary": "8",
+                                "C": "-0.00000000",
+                                "D": "-3.00000000",
+                                "fiber-type": "smf"
+                            },
+                            {
+                                "lower-boundary": "8",
+                                "upper-boundary": "23",
+                                "C": "0.33333334",
+                                "D": "-5.66666667",
+                                "fiber-type": "smf"
+                            },
+                            {
+                                "lower-boundary": "23",
+                                "upper-boundary": "27",
+                                "C": "0.00000000",
+                                "D": "2.00000000",
+                                "fiber-type": "smf"
+                            }
+                        ]
+                    }
+                },
+                "Drop": {
+                    "openroadm-operational-mode": {
+                        "openroadm-operational-mode-id": "MW-WR-core",
+                        "per-channel-Pin-min": "-25.000",
+                        "per-channel-Pin-max": "-9.000",
+                        "max-introduced-pdl": "1.500",
+                        "max-introduced-dgd": "3.00",
+                        "max-introduced-cd": "25.00",
+                        "osnr-polynomial-fit": {
+                            "A": "-0.00059520",
+                            "B": "-0.06250000",
+                            "C": "-1.07100000",
+                            "D": "27.99000000"
+                        },
+                        "per-channel-Pout-min": "-22.000",
+                        "per-channel-Pout-max": "1.000"
+                    }
+                }
+            },
+            "amplifiers": {
+                "Amplifier": {
+                    "min-gain": "0.000",
+                    "max-gain": "27.000",
+                    "max-extended-gain": "31.000",
+                    "mask-gain-ripple-vs-tilt": [
+                        {
+                            "lower-boundary": "-4",
+                            "upper-boundary": "-1",
+                            "C": "-0.50",
+                            "D": "1.00"
+                        },
+                        {
+                            "lower-boundary": "-1",
+                            "upper-boundary": "0",
+                            "C": "0.50",
+                            "D": "2.00"
+                        }
+                    ],
+                    "openroadm-operational-mode": [
+                        {
+                            "openroadm-operational-mode-id": "MWi-standard",
+                            "per-channel-Pin-min": "-31.000",
+                            "per-channel-Pin-max": "-9.000",
+                            "max-introduced-pdl": "0.70",
+                            "max-introduced-dgd": "3.00",
+                            "max-introduced-cd": "0.00",
+                            "osnr-polynomial-fit": {
+                                "A": "-0.00059520",
+                                "B": "-0.06250000",
+                                "C": "-1.07100000",
+                                "D": "28.99000000"
+                            },
+                            "per-channel-Pout-min": "-9.000",
+                            "per-channel-Pout-max": "2.000"
+                        },
+                        {
+                            "openroadm-operational-mode-id": "MWi-low-noise",
+                            "per-channel-Pin-min": "-31.000",
+                            "per-channel-Pin-max": "-9.000",
+                            "max-introduced-pdl": "0.700",
+                            "max-introduced-dgd": "3.00",
+                            "max-introduced-cd": "0.00",
+                            "osnr-polynomial-fit": {
+                                "A": "-0.00081040",
+                                "B": "-0.06221000",
+                                "C": "-0.58890000",
+                                "D": "37.62000000"
+                            },
+                            "per-channel-Pout-min": "-9.000",
+                            "per-channel-Pout-max": "2.000"
+                        }
+                    ]
+                }
+            }
+        }
+    }
+}
diff --git a/pce/src/test/resources/topologyData/or-base-topology.json b/pce/src/test/resources/topologyData/or-base-topology.json
new file mode 100644 (file)
index 0000000..0dbcc99
--- /dev/null
@@ -0,0 +1,2733 @@
+{
+    "ietf-network:networks": {
+        "network": {
+            "network-id": "openroadm-topology",
+            "ietf-network-topology:link": [
+                {
+                    "link-id": "XPONDER-1XPDR-NW1-TX-toOpenROADM-1-SRG1-SRG1-PP1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "XPONDER-1",
+                        "source-tp": "XPDR-NW1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-OUTPUT",
+                    "destination": {
+                        "dest-node": "OpenROADM-1-SRG1",
+                        "dest-tp": "SRG1-PP1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-SRG1-SRG1-PP1-TX-to-XPONDER-1XPDR-NW1-RX"
+                },
+                {
+                    "link-id": "XPONDER-2XPDR-NW1-TX-toOpenROADM-2-SRG1-SRG1-PP1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "XPONDER-2",
+                        "source-tp": "XPDR-NW1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-OUTPUT",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-SRG1",
+                        "dest-tp": "SRG1-PP1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-SRG1-SRG1-PP1-TX-to-XPONDER-2XPDR-NW1-RX"
+                },
+                {
+                    "link-id": "XPONDER-3XPDR-NW1-TX-toOpenROADM-3-SRG1-SRG1-PP1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "XPONDER-3",
+                        "source-tp": "XPDR-NW1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-OUTPUT",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-SRG1",
+                        "dest-tp": "SRG1-PP1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-SRG1-SRG1-PP1-TX-to-XPONDER-3XPDR-NW1-RX"
+                },
+                {
+                    "link-id": "XPONDER-4XPDR-NW1-TX-toOpenROADM-4-SRG1-SRG1-PP1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "XPONDER-4",
+                        "source-tp": "XPDR-NW1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-OUTPUT",
+                    "destination": {
+                        "dest-node": "OpenROADM-4-SRG1",
+                        "dest-tp": "SRG1-PP1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-SRG1-SRG1-PP1-TX-to-XPONDER-4XPDR-NW1-RX"
+                },
+                {
+                    "link-id": "XPONDER-5XPDR-NW1-TX-toOpenROADM-5-SRG1-SRG1-PP1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "XPONDER-5",
+                        "source-tp": "XPDR-NW1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-OUTPUT",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-SRG1",
+                        "dest-tp": "SRG1-PP1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-SRG1-SRG1-PP1-TX-to-XPONDER-5XPDR-NW1-RX"
+                },
+                {
+                    "link-id": "OpenROADM-1-SRG1-SRG1-PP1-TX-to-XPONDER-1XPDR-NW1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-SRG1",
+                        "source-tp": "SRG1-PP1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-INPUT",
+                    "destination": {
+                        "dest-node": "XPONDER-1",
+                        "dest-tp": "XPDR-NW1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "XPONDER-1XPDR-NW1-TX-toOpenROADM-1-SRG1-SRG1-PP1-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-SRG1-SRG1-PP1-TX-to-XPONDER-2XPDR-NW1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-SRG1",
+                        "source-tp": "SRG1-PP1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-INPUT",
+                    "destination": {
+                        "dest-node": "XPONDER-2",
+                        "dest-tp": "XPDR-NW1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "XPONDER-2XPDR-NW1-TX-toOpenROADM-2-SRG1-SRG1-PP1-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-SRG1-SRG1-PP1-TX-to-XPONDER-3XPDR-NW1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-SRG1",
+                        "source-tp": "SRG1-PP1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-INPUT",
+                    "destination": {
+                        "dest-node": "XPONDER-3",
+                        "dest-tp": "XPDR-NW1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "XPONDER-3XPDR-NW1-TX-toOpenROADM-3-SRG1-SRG1-PP1-RX"
+                },
+                {
+                    "link-id": "OpenROADM-4-SRG1-SRG1-PP1-TX-to-XPONDER-4XPDR-NW1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-SRG1",
+                        "source-tp": "SRG1-PP1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-INPUT",
+                    "destination": {
+                        "dest-node": "XPONDER-4",
+                        "dest-tp": "XPDR-NW1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "XPONDER-4XPDR-NW1-TX-toOpenROADM-4-SRG1-SRG1-PP1-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-SRG1-SRG1-PP1-TX-to-XPONDER-5XPDR-NW1-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-SRG1",
+                        "source-tp": "SRG1-PP1-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "XPONDER-INPUT",
+                    "destination": {
+                        "dest-node": "XPONDER-5",
+                        "dest-tp": "XPDR-NW1-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "XPONDER-5XPDR-NW1-TX-toOpenROADM-5-SRG1-SRG1-PP1-RX"
+                },
+                {
+                    "link-id": "OpenROADM-1-SRG1-SRG1-CP-TXtoOpenROADM-1-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-1-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-DEG1-DEG1-CTP-TXtoOpenROADM-1-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-1-SRG1-SRG1-CP-TXtoOpenROADM-1-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-1-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-DEG2-DEG2-CTP-TXtoOpenROADM-1-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-SRG1-SRG1-CP-TXtoOpenROADM-2-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG1-DEG1-CTP-TXtoOpenROADM-2-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-SRG1-SRG1-CP-TXtoOpenROADM-2-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG2-DEG2-CTP-TXtoOpenROADM-2-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-SRG1-SRG1-CP-TXtoOpenROADM-2-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG3-DEG3-CTP-TXtoOpenROADM-2-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-SRG1-SRG1-CP-TXtoOpenROADM-3-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG1-DEG1-CTP-TXtoOpenROADM-3-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-SRG1-SRG1-CP-TXtoOpenROADM-3-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG2-DEG2-CTP-TXtoOpenROADM-3-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-SRG1-SRG1-CP-TXtoOpenROADM-3-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG3-DEG3-CTP-TXtoOpenROADM-3-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-SRG1-SRG1-CP-TXtoOpenROADM-3-DEG4-DEG4-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG4",
+                        "dest-tp": "DEG4-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG4-DEG4-CTP-TXtoOpenROADM-3-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-4-SRG1-SRG1-CP-TXtoOpenROADM-4-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-4-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-DEG1-DEG1-CTP-TXtoOpenROADM-4-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-4-SRG1-SRG1-CP-TXtoOpenROADM-4-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-4-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-DEG2-DEG2-CTP-TXtoOpenROADM-4-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-SRG1-SRG1-CP-TXtoOpenROADM-5-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG1-DEG1-CTP-TXtoOpenROADM-5-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-SRG1-SRG1-CP-TXtoOpenROADM-5-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG2-DEG2-CTP-TXtoOpenROADM-5-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-SRG1-SRG1-CP-TXtoOpenROADM-5-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-SRG1",
+                        "source-tp": "SRG1-CP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "ADD-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG3-DEG3-CTP-TXtoOpenROADM-5-SRG1-SRG1-CP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-1-DEG1-DEG1-CTP-TXtoOpenROADM-1-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-1-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-SRG1-SRG1-CP-TXtoOpenROADM-1-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-1-DEG2-DEG2-CTP-TXtoOpenROADM-1-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-1-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-SRG1-SRG1-CP-TXtoOpenROADM-1-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG1-DEG1-CTP-TXtoOpenROADM-2-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-SRG1-SRG1-CP-TXtoOpenROADM-2-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG2-DEG2-CTP-TXtoOpenROADM-2-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-SRG1-SRG1-CP-TXtoOpenROADM-2-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG3-DEG3-CTP-TXtoOpenROADM-2-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-SRG1-SRG1-CP-TXtoOpenROADM-2-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG1-DEG1-CTP-TXtoOpenROADM-3-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-SRG1-SRG1-CP-TXtoOpenROADM-3-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG2-DEG2-CTP-TXtoOpenROADM-3-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-SRG1-SRG1-CP-TXtoOpenROADM-3-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG3-DEG3-CTP-TXtoOpenROADM-3-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-SRG1-SRG1-CP-TXtoOpenROADM-3-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG4-DEG4-CTP-TXtoOpenROADM-3-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG4",
+                        "source-tp": "DEG4-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-SRG1-SRG1-CP-TXtoOpenROADM-3-DEG4-DEG4-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-4-DEG1-DEG1-CTP-TXtoOpenROADM-4-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-4-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-SRG1-SRG1-CP-TXtoOpenROADM-4-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-4-DEG2-DEG2-CTP-TXtoOpenROADM-4-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-4-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-SRG1-SRG1-CP-TXtoOpenROADM-4-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG1-DEG1-CTP-TXtoOpenROADM-5-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-SRG1-SRG1-CP-TXtoOpenROADM-5-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG2-DEG2-CTP-TXtoOpenROADM-5-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-SRG1-SRG1-CP-TXtoOpenROADM-5-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG3-DEG3-CTP-TXtoOpenROADM-5-SRG1-SRG1-CP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "DROP-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-SRG1",
+                        "dest-tp": "SRG1-CP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-SRG1-SRG1-CP-TXtoOpenROADM-5-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-1-DEG1-to-OpenROADM-2-DEG1",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-DEG1",
+                        "source-tp": "DEG1-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 20.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 2.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 20.0,
+                            "engineered-spanloss": 20.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber12",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG1",
+                        "dest-tp": "DEG1-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG1-to-OpenROADM-1-DEG1"
+                },
+                {
+                    "link-id": "OpenROADM-1-DEG2-to-OpenROADM-3-DEG1",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-DEG2",
+                        "source-tp": "DEG2-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 28.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 0.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 28.0,
+                            "engineered-spanloss": 28.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber13",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG1",
+                        "dest-tp": "DEG1-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG1-to-OpenROADM-1-DEG2"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG1-to-OpenROADM-1-DEG1",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG1",
+                        "source-tp": "DEG1-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 20.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 2.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 20.0,
+                            "engineered-spanloss": 20.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber21",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-1-DEG1",
+                        "dest-tp": "DEG1-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-DEG1-to-OpenROADM-2-DEG1"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG2-to-OpenROADM-3-DEG2",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG2",
+                        "source-tp": "DEG2-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 5.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 10000,
+                                    "pmd": 32.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 5.0,
+                            "engineered-spanloss": 5.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber23",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG2",
+                        "dest-tp": "DEG2-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG2-to-OpenROADM-2-DEG2"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG3-to-OpenROADM-5-DEG3",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG3",
+                        "source-tp": "DEG3-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 20.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 2.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 20.0,
+                            "engineered-spanloss": 20.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber25",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG3",
+                        "dest-tp": "DEG3-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG3-to-OpenROADM-2-DEG3"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG1-to-OpenROADM-1-DEG2",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG1",
+                        "source-tp": "DEG1-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 28.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 0.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 28.0,
+                            "engineered-spanloss": 28.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber31",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-1-DEG2",
+                        "dest-tp": "DEG2-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-DEG2-to-OpenROADM-3-DEG1"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG2-to-OpenROADM-2-DEG2",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG2",
+                        "source-tp": "DEG2-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 5.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 10000,
+                                    "pmd": 30.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 5.0,
+                            "engineered-spanloss": 5.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber32",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG2",
+                        "dest-tp": "DEG2-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG2-to-OpenROADM-3-DEG2"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG3-to-OpenROADM-5-DEG2",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG3",
+                        "source-tp": "DEG3-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 25.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 32.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 25.0,
+                            "engineered-spanloss": 25.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber35",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG2",
+                        "dest-tp": "DEG2-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG2-to-OpenROADM-3-DEG3"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG4-to-OpenROADM-4-DEG2",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG4",
+                        "source-tp": "DEG2-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 25.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 2.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 25.0,
+                            "engineered-spanloss": 25.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber34",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-4-DEG2",
+                        "dest-tp": "DEG2-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-DEG2-to-OpenROADM-3-DEG4"
+                },
+                {
+                    "link-id": "OpenROADM-4-DEG1-to-OpenROADM-5-DEG1",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-DEG1",
+                        "source-tp": "DEG1-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 25.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 2.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 25.0,
+                            "engineered-spanloss": 25.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber45",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG1",
+                        "dest-tp": "DEG1-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG1-to-OpenROADM-4-DEG1"
+                },
+                {
+                    "link-id": "OpenROADM-4-DEG2-to-OpenROADM-3-DEG4",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-DEG2",
+                        "source-tp": "DEG2-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 25.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 2.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 25.0,
+                            "engineered-spanloss": 25.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber43",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG4",
+                        "dest-tp": "DEG4-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG4-to-OpenROADM-4-DEG2"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG1-to-OpenROADM-4-DEG1",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG1",
+                        "source-tp": "DEG1-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 25.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 2.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 25.0,
+                            "engineered-spanloss": 25.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber54",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-4-DEG1",
+                        "dest-tp": "DEG1-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-DEG1-to-OpenROADM-5-DEG1"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG2-to-OpenROADM-3-DEG3",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG2",
+                        "source-tp": "DEG2-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 25.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 0.5,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 25.0,
+                            "engineered-spanloss": 25.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber53",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG3",
+                        "dest-tp": "DEG3-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG3-to-OpenROADM-5-DEG2"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG3-to-OpenROADM-2-DEG3",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG3",
+                        "source-tp": "DEG3-TTP-TX"
+                    },
+                    "org-openroadm-network-topology:OMS-attributes": {
+                        "span": {
+                            "spanloss-base": 20.0,
+                            "link-concatenation": [
+                                {
+                                    "SRLG-Id": 0,
+                                    "SRLG-length": 100000,
+                                    "pmd": 2.0,
+                                    "fiber-type": "smf"
+                                }
+                            ],
+                            "spanloss-current": 20.0,
+                            "engineered-spanloss": 20.0,
+                            "auto-spanloss": true
+                        }
+                    },
+                    "org-openroadm-common-network:link-type": "ROADM-TO-ROADM",
+                    "org-openroadm-common-network:clfi": "fiber52",
+                    "org-openroadm-common-network:TE-metric": 10,
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG3",
+                        "dest-tp": "DEG3-TTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG3-to-OpenROADM-5-DEG3"
+                },
+                {
+                    "link-id": "OpenROADM-1-DEG1-DEG1-CTP-TXtoOpenROADM-1-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-1-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-DEG2-DEG2-CTP-TXtoOpenROADM-1-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-1-DEG2-DEG2-CTP-TXtoOpenROADM-1-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-1-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-1-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-1-DEG1-DEG1-CTP-TXtoOpenROADM-1-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG1-DEG1-CTP-TXtoOpenROADM-2-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG2-DEG2-CTP-TXtoOpenROADM-2-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG1-DEG1-CTP-TXtoOpenROADM-2-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG3-DEG3-CTP-TXtoOpenROADM-2-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG2-DEG2-CTP-TXtoOpenROADM-2-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG1-DEG1-CTP-TXtoOpenROADM-2-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG2-DEG2-CTP-TXtoOpenROADM-2-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG3-DEG3-CTP-TXtoOpenROADM-2-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG3-DEG3-CTP-TXtoOpenROADM-2-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG1-DEG1-CTP-TXtoOpenROADM-2-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-2-DEG3-DEG3-CTP-TXtoOpenROADM-2-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-2-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-2-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-2-DEG2-DEG2-CTP-TXtoOpenROADM-2-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG1-DEG1-CTP-TXtoOpenROADM-3-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG2-DEG2-CTP-TXtoOpenROADM-3-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG1-DEG1-CTP-TXtoOpenROADM-3-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG3-DEG3-CTP-TXtoOpenROADM-3-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG1-DEG1-CTP-TXtoOpenROADM-3-DEG4-DEG4-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG4",
+                        "dest-tp": "DEG4-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG4-DEG4-CTP-TXtoOpenROADM-3-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG2-DEG2-CTP-TXtoOpenROADM-3-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG1-DEG1-CTP-TXtoOpenROADM-3-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG2-DEG2-CTP-TXtoOpenROADM-3-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG3-DEG3-CTP-TXtoOpenROADM-3-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG2-DEG2-CTP-TXtoOpenROADM-3-DEG4-DEG4-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG4",
+                        "dest-tp": "DEG4-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG4-DEG4-CTP-TXtoOpenROADM-3-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG3-DEG3-CTP-TXtoOpenROADM-3-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG1-DEG1-CTP-TXtoOpenROADM-3-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG3-DEG3-CTP-TXtoOpenROADM-3-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG2-DEG2-CTP-TXtoOpenROADM-3-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG3-DEG3-CTP-TXtoOpenROADM-3-DEG4-DEG4-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG4",
+                        "dest-tp": "DEG4-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG4-DEG4-CTP-TXtoOpenROADM-3-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG4-DEG4-CTP-TXtoOpenROADM-3-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG4",
+                        "source-tp": "DEG4-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG1-DEG1-CTP-TXtoOpenROADM-3-DEG4-DEG4-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG4-DEG4-CTP-TXtoOpenROADM-3-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG4",
+                        "source-tp": "DEG4-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG2-DEG2-CTP-TXtoOpenROADM-3-DEG4-DEG4-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-3-DEG4-DEG4-CTP-TXtoOpenROADM-3-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-3-DEG4",
+                        "source-tp": "DEG4-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-3-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-3-DEG3-DEG3-CTP-TXtoOpenROADM-3-DEG4-DEG4-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-4-DEG1-DEG1-CTP-TXtoOpenROADM-4-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-4-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-DEG2-DEG2-CTP-TXtoOpenROADM-4-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-4-DEG2-DEG2-CTP-TXtoOpenROADM-4-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-4-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-4-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-4-DEG1-DEG1-CTP-TXtoOpenROADM-4-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG1-DEG1-CTP-TXtoOpenROADM-5-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG2-DEG2-CTP-TXtoOpenROADM-5-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG1-DEG1-CTP-TXtoOpenROADM-5-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG1",
+                        "source-tp": "DEG1-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG3-DEG3-CTP-TXtoOpenROADM-5-DEG1-DEG1-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG2-DEG2-CTP-TXtoOpenROADM-5-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG1-DEG1-CTP-TXtoOpenROADM-5-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG2-DEG2-CTP-TXtoOpenROADM-5-DEG3-DEG3-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG2",
+                        "source-tp": "DEG2-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG3",
+                        "dest-tp": "DEG3-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG3-DEG3-CTP-TXtoOpenROADM-5-DEG2-DEG2-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG3-DEG3-CTP-TXtoOpenROADM-5-DEG1-DEG1-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG1",
+                        "dest-tp": "DEG1-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG1-DEG1-CTP-TXtoOpenROADM-5-DEG3-DEG3-CTP-RX"
+                },
+                {
+                    "link-id": "OpenROADM-5-DEG3-DEG3-CTP-TXtoOpenROADM-5-DEG2-DEG2-CTP-RX",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "source": {
+                        "source-node": "OpenROADM-5-DEG3",
+                        "source-tp": "DEG3-CTP-TX"
+                    },
+                    "org-openroadm-common-network:link-type": "EXPRESS-LINK",
+                    "destination": {
+                        "dest-node": "OpenROADM-5-DEG2",
+                        "dest-tp": "DEG2-CTP-RX"
+                    },
+                    "org-openroadm-common-network:opposite-link": "OpenROADM-5-DEG2-DEG2-CTP-TXtoOpenROADM-5-DEG3-DEG3-CTP-RX"
+                }
+            ],
+            "node": [
+                {
+                    "node-id": "OpenROADM-1-SRG1",
+                    "operational-state": "inService",
+                    "administrative-state": "inService",
+                    "ietf-network-topology:termination-point": [
+                        {
+                            "tp-id": "SRG1-CP-RX",
+                            "operational-state": "inService",
+                            "administrative-state": "inService",
+                            "org-openroadm-common-network:tp-type": "SRG-RX-CP"
+                        },
+                        {
+                            "tp-id": "SRG1-PP1-RX",
+                            "operational-state": "inService",
+                            "administrative-state": "inService",
+                            "org-openroadm-common-network:tp-type": "SRG-RX-PP"
+                        },
+                        {
+                            "tp-id": "SRG1-PP2-TX",
+                            "org-openroadm-common-network:tp-type": "SRG-TX-PP"
+                        },
+                        {
+                            "tp-id": "SRG1-CP-TX",
+                            "operational-state": "inService",
+                            "administrative-state": "inService",
+                            "org-openroadm-common-network:tp-type": "SRG-TX-CP"
+                        },
+                        {
+                            "tp-id": "SRG1-PP1-TX",
+                            "operational-state": "inService",
+                            "administrative-state": "inService",
+                            "org-openroadm-common-network:tp-type": "SRG-TX-PP"
+                        },
+                        {
+                            "tp-id": "SRG1-PP2-RX",
+                            "org-openroadm-common-network:tp-type": "SRG-RX-PP"
+                        }
+                    ],
+                    "org-openroadm-network-topology:srg-attributes": {
+                        "avail-freq-maps": [
+                            {
+                                "map-name": "cband",
+                                "start-edge-freq": 191.325,
+                                "freq-map-granularity": 6.25,
+                                "effective-bits": 8,
+                                "freq-map": "AP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+                            }
+                        ]
+                    },
+                    "org-openroadm-common-network:node-type": "SRG",
+                    "supporting-node": [
+                        {
+                            "network-ref": "openroadm-network",
+                            "node-ref": "OpenROADM-1"
+                        },
+                        {
+                            "network-ref": "clli-network",
+                            "node-ref": "Node1"
+                        }
+                    ]
+           &nb