+ for (int pathElement = 2 + bypassDegree; pathElement < vertices.size() - 1; pathElement++) {
+ PceNode currentNode = allPceNodes.get(new NodeId(vertices.get(pathElement)));
+ PceNode nextNode = allPceNodes.get(new NodeId(vertices.get(pathElement + 1)));
+ LOG.debug("loop of check OSNR direction AZ: Path Element = {}", pathElement);
+ switch (currentNode.getORNodeType()) {
+ case SRG:
+ LOG.debug("loop of check OSNR direction AZ: SRG, Path Element = {}", pathElement);
+ // Other case is DROP, for which cnt is unchanged (.DROP)
+ if (edges.get(pathElement - 1).link().getlinkType() != OpenroadmLinkType.DROPLINK) {
+ LOG.error("Error processing Node {} for which input link {} is not a DROPLINK Type",
+ currentNode.getNodeId(), pathElement - 1);
+ }
+ PceLink pceLink = edges.get(pathElement - 2).link();
+ LOG.info("loop of check OSNR : SRG, pathElement = {} CD on preceeding link {} = {} ps",
+ pathElement, pathElement - 2, pceLink.getcd());
+ calcDropContrib(cu, signal, currentNode, pceLink);
+ double calcOnsr = signal.get("calcOnsrLin").doubleValue();
+ if (calcOnsr == Double.NEGATIVE_INFINITY || calcOnsr == Double.POSITIVE_INFINITY) {
+ return -1.0;
+ }
+ // 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 {
+ calcOnsrdB = getOsnrDbfromOnsrLin(calcOnsr);
+ LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOnsrdB);
+ LOG.info("Loop pathElement = {}, DROP, calcOnsrdB= {}", pathElement, calcOnsrdB);
+ } catch (ArithmeticException e) {
+ LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}",
+ path.getEdgeList().size());
+ return -1.0;
+ }
+ 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 direction AZ: DEGREE, Path Element = {}", pathElement);
+ calcBypassContrib(cu, signal, currentNode, nextNode,
+ edges.get(pathElement - 1).link(), edges.get(pathElement + 1).link());
+ double calcOnsrLin = signal.get("calcOnsrLin").doubleValue();
+ LOG.debug(
+ "Loop pathElement= {}, DEGREE, calcOnsrdB= {}", pathElement, 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
+ pathElement++;
+ LOG.info("Accumulated degradations in the path including ROADM {} + {} are CD: {}; PMD2: "
+ + "{}; Pdl2 : {}; ONSRdB : {}", currentNode.getNodeId(), nextNode.getNodeId(),
+ signal.get("calcCd"), signal.get("calcPmd2"), signal.get("calcPdl2"),
+ getOsnrDbfromOnsrLin(calcOnsrLin));
+ break;
+ case XPONDER:
+ LOG.debug("loop of check OSNR direction AZ: XPDR, Path Element = {}", pathElement);
+ LOG.error("unsupported back to back transponder configuration");
+ return -1.0;
+ default:
+ LOG.error("PostAlgoPathValidator.CheckOSNR : unsupported resource type in the path chain");
+ }
+ }
+ PceNode currentNode = allPceNodes.get(new NodeId(vertices.get(vertices.size() - 1)));
+ LOG.debug("loop of check OSNR, Path Element = {}", vertices.size() - 1);
+ switch (currentNode.getORNodeType()) {
+ case XPONDER:
+ LOG.debug("loop of check OSNR direction AZ: XPDR, Path Element = {}", vertices.size() - 1);
+ transponderPresent = true;
+ // TSP is the last of the path
+ margin = getLastXpdrMargin(cu, signal, edges.get(vertices.size() - 2).link().getDestTP().getValue(),
+ serviceType, currentNode, vertices.get(vertices.size() - 1), vertices.size() - 1);
+ break;
+ case SRG:
+ LOG.debug("loop of check OSNR direction AZ: SRG, Path Element = {}", vertices.size() - 1);
+ // Other case is DROP, for which cnt is unchanged (.DROP)
+ if (edges.get(vertices.size() - 2).link().getlinkType() != OpenroadmLinkType.DROPLINK) {
+ LOG.error("Error processing Node {} for which input link {} is not a DROPLINK Type",
+ currentNode.getNodeId(), vertices.size() - 2);
+ }
+ PceLink pceLink = edges.get(vertices.size() - 3).link();
+ LOG.info("loop of check OSNR : SRG, pathElement = {} CD on preceeding link {} = {} ps",
+ vertices.size() - 1, vertices.size() - 3, pceLink.getcd());
+ calcDropContrib(cu, signal, currentNode, pceLink);
+ double calcOnsr = signal.get("calcOnsrLin").doubleValue();
+ //commented out to avoid spotbug DLS_DEAD_LOCAL_STORE pwrIn = impairments.get("pwrIn");
+ if (calcOnsr == Double.NEGATIVE_INFINITY || calcOnsr == Double.POSITIVE_INFINITY) {
+ return -1.0;
+ }
+ // 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 {
+ calcOnsrdB = getOsnrDbfromOnsrLin(calcOnsr);
+ LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOnsrdB);
+ LOG.info("Loop pathElement = {}, DROP, calcOnsrdB= {}", vertices.size() - 1, calcOnsrdB);
+ } catch (ArithmeticException e) {
+ LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}",
+ path.getEdgeList().size());
+ return -1.0;
+ }
+ break;
+ case DEGREE:
+ default:
+ LOG.error("PostAlgoPathValidator.CheckOSNR : unsupported resource type in the path chain last element");
+ }
+ LOG.info("- In checkOSNR: accumulated CD = {} ps, PMD = {} ps, PDL = {} dB, and resulting OSNR calcOnsrdB = {} "
+ + "dB and ONSR dB exterapolated from calcosnrlin = {} including non linear contributions",
+ signal.get("calcCd"), Math.sqrt(signal.get("calcPmd2").doubleValue()),
+ Math.sqrt(signal.get("calcPdl2").doubleValue()), calcOnsrdB,
+ getOsnrDbfromOnsrLin(signal.get("calcOnsrLin").doubleValue()));
+ 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;
+ }
+ double delta = margin - SYS_MARGIN;
+ 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.",
+ delta, SYS_MARGIN);
+ String validationMessage = delta >= 0 ? "VALIDATED" : "INVALIDATED";
+ LOG.info("- In checkOSNR: A to Z Path from {} to {} {}",
+ vertices.get(0), vertices.get(vertices.size() - 1), validationMessage);
+ return delta;
+ }
+
+ /**
+ * 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 cu CatalogUtils instance.
+ * @return the calculated margin according to the Transponder performances and path impairments.
+ */
+ private double checkOSNRza(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
+ Map<LinkId, PceLink> allPceLinks, String serviceType, CatalogUtils cu) {
+ Map<String, Double> signal = new HashMap<>(
+ Map.of(
+ "spacing", Double.valueOf(50.0),
+ "calcPdl2", Double.valueOf(0),
+ "calcCd", Double.valueOf(0),
+ "calcPmd2", Double.valueOf(0),
+ "calcOnsrLin", Double.valueOf(0.0001),
+ "pwrIn", Double.valueOf(-60.0),
+ "pwrOut", Double.valueOf(-60.0)));
+ double calcOnsrdB = 0;
+ double margin = 0;
+ boolean transponderPresent = false;
+ List<String> vertices = path.getVertexList();
+ List<PceGraphEdge> edges = path.getEdgeList();
+ // 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
+ int bypassDegree = 0;
+ for (int pathElement = vertices.size() - 1; pathElement > vertices.size() - 3; pathElement--) {
+ bypassDegree = 0;
+ PceNode currentNode = allPceNodes.get(new NodeId(vertices.get(pathElement)));
+ PceNode nextNode = allPceNodes.get(new NodeId(vertices.get(pathElement - 1)));
+ LOG.debug("loop of check OSNR direction ZA: Path Element = {}", pathElement);
+ switch (currentNode.getORNodeType()) {
+ case XPONDER:
+ LOG.debug("loop of check OSNR direction ZA: XPDR, Path Element = {}", pathElement);
+ transponderPresent = true;
+ calcXpdrOSNR(cu, signal,
+ pathElement == vertices.size() - 1
+ // First transponder on the Path (TX side) / Last Xponder of the path (RX side)
+ ? getOppPceLink(pathElement - 1, edges, allPceLinks).getSourceTP().getValue()
+ : getOppPceLink((pathElement), edges, allPceLinks).getDestTP().getValue(),
+ serviceType, currentNode, nextNode, vertices.get(pathElement), pathElement);
+ break;
+ case SRG:
+ LOG.debug("loop of check OSNR direction ZA: SRG, Path Element = {}", pathElement);
+ // 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 (getOppPceLink(pathElement - 1, edges, allPceLinks).getlinkType() != OpenroadmLinkType.ADDLINK) {
+ LOG.error("Error processing Node {} for which output link {} is not an ADDLINK Type",
+ currentNode.getNodeId(), pathElement - 1);
+ }
+ signal.put("pwrIn", Double.valueOf(0));
+ calcAddContrib(cu, signal, currentNode, getOppPceLink(pathElement - 2, edges, allPceLinks));
+ double calcOnsr = signal.get("calcOnsrLin").doubleValue();
+ if (calcOnsr == Double.NEGATIVE_INFINITY || calcOnsr == Double.POSITIVE_INFINITY) {
+ return -1.0;
+ }
+ // 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.
+ pathElement--;
+ bypassDegree = 1;
+ break;
+ case DEGREE:
+ default:
+ LOG.error("PostAlgoPathValidator.CheckOSNR : unsupported resource type in the path chain");
+ }
+ }
+ for (int pathElement = vertices.size() - 3 - bypassDegree; pathElement > 0; pathElement--) {
+ PceNode currentNode = allPceNodes.get(new NodeId(vertices.get(pathElement)));
+ PceNode nextNode = allPceNodes.get(new NodeId(vertices.get(pathElement - 1)));
+ LOG.debug("loop of check OSNR direction ZA: Path Element = {}", pathElement);
+ switch (currentNode.getORNodeType()) {
+ case SRG:
+ LOG.debug("loop of check OSNR direction ZA: SRG, Path Element = {}", pathElement);
+ if (getOppPceLink(pathElement, edges, allPceLinks).getlinkType() != OpenroadmLinkType.DROPLINK) {
+ LOG.error("Error processing Node {} for which input link {} is not a DROPLINK Type",
+ currentNode.getNodeId(), pathElement);
+ }
+ PceLink pceLink = getOppPceLink(pathElement + 1, edges, allPceLinks);
+ LOG.info("loop of check OSNR direction ZA: SRG, path Element = {} CD on preceeding link {} = {} ps",
+ pathElement, pathElement + 1, pceLink.getcd());
+ calcDropContrib(cu, signal, currentNode, pceLink);
+ double calcOnsr = signal.get("calcOnsrLin").doubleValue();
+ if (calcOnsr == Double.NEGATIVE_INFINITY || calcOnsr == Double.POSITIVE_INFINITY) {
+ return -1.0;
+ }
+ // 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 {
+ calcOnsrdB = getOsnrDbfromOnsrLin(calcOnsr);
+ LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOnsrdB);
+ LOG.info("Loop Path Element = {}, DROP, calcOnsrdB= {}", pathElement, calcOnsrdB);
+ } catch (ArithmeticException e) {
+ LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}",
+ path.getEdgeList().size());
+ return -1.0;
+ }
+ 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 direction ZA: DEGREE, Path Element = {}", pathElement);
+ calcBypassContrib(cu, signal, currentNode, nextNode,
+ getOppPceLink(pathElement, edges, allPceLinks),
+ getOppPceLink(pathElement - 2, edges, allPceLinks));
+ double calcOnsrLin = signal.get("calcOnsrLin").doubleValue();
+ LOG.debug("Loop Path Element = {}, DEGREE, calcOnsrdB= {}",
+ pathElement, 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
+ pathElement--;
+ LOG.info("Accumulated degradations in the path including ROADM {} + {} are CD: {}; PMD2: "
+ + "{}; Pdl2 : {}; ONSRdB : {}", currentNode.getNodeId(), nextNode.getNodeId(),
+ signal.get("calcCd"), signal.get("calcPmd2"), signal.get("calcPdl2"),
+ getOsnrDbfromOnsrLin(calcOnsrLin));
+ break;
+ case XPONDER:
+ LOG.debug("loop of check OSNR direction AZ: XPDR, Path Element = {}", pathElement);
+ LOG.error("unsupported back to back transponder configuration");
+ return -1.0;
+ default:
+ LOG.error("PostAlgoPathValidator.CheckOSNR : unsupported resource type in the path chain");
+ }
+ }
+ PceNode currentNode = allPceNodes.get(new NodeId(vertices.get(0)));
+ LOG.debug("loop of check OSNR direction ZA: Path Element = 0");
+ switch (currentNode.getORNodeType()) {
+ case XPONDER:
+ LOG.debug("loop of check OSNR direction ZA: XPDR, Path Element = 0");
+ transponderPresent = true;
+ // TSP is the last of the path
+ margin = getLastXpdrMargin(cu, signal, getOppPceLink(0, edges, allPceLinks).getDestTP().getValue(),
+ serviceType, currentNode, vertices.get(0), 0);
+ break;
+ case SRG:
+ LOG.debug("loop of check OSNR direction ZA: SRG, Path Element = 0");
+ if (getOppPceLink(0, edges, allPceLinks).getlinkType() != OpenroadmLinkType.DROPLINK) {
+ LOG.error("Error processing Node {} for which input link 0 is not a DROPLINK Type",
+ currentNode.getNodeId());
+ }
+ PceLink pceLink = getOppPceLink(1, edges, allPceLinks);
+ LOG.info("loop of check OSNR direction ZA: SRG, path Element = 0 CD on preceeding link 1 = {} ps",
+ pceLink.getcd());
+ calcDropContrib(cu, signal, currentNode, pceLink);
+ double calcOnsr = signal.get("calcOnsrLin").doubleValue();
+ //commented out to avoid spotbug DLS_DEAD_LOCAL_STORE pwrIn = impairments.get("pwrIn");
+ if (calcOnsr == Double.NEGATIVE_INFINITY || calcOnsr == Double.POSITIVE_INFINITY) {
+ return -1.0;
+ }
+ // 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 {
+ calcOnsrdB = getOsnrDbfromOnsrLin(calcOnsr);
+ LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOnsrdB);
+ LOG.info("Loop Path Element = 0, DROP, calcOnsrdB= {}", calcOnsrdB);
+ } catch (ArithmeticException e) {
+ LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}",
+ path.getEdgeList().size());
+ return -1.0;
+ }
+ break;
+ case DEGREE:
+ default:
+ LOG.error("PostAlgoPathValidator.CheckOSNR : unsupported resource type in the path chain last element");
+ }
+ LOG.info("- In checkOSNR: accumulated CD = {} ps, PMD = {} ps, PDL = {} dB, and resulting OSNR calcOnsrdB = {} "
+ + "dB and ONSR dB exterapolated from calcosnrlin = {} including non linear contributions",
+ signal.get("calcCd"), Math.sqrt(signal.get("calcPmd2").doubleValue()),
+ Math.sqrt(signal.get("calcPdl2").doubleValue()), calcOnsrdB,
+ getOsnrDbfromOnsrLin(signal.get("calcOnsrLin").doubleValue()));
+ 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;
+ }
+ double delta = margin - SYS_MARGIN;
+ 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.",
+ delta, SYS_MARGIN);
+ String validationMessage = delta >= 0 ? "VALIDATED" : "INVALIDATED";
+ LOG.info("- In checkOSNR: Z to A Path from {} to {} {}",
+ vertices.get(vertices.size() - 1), vertices.get(0), validationMessage);
+ return delta;
+ }
+
+ private String setOpMode(String opMode, String defaultMode) {
+ return
+ opMode == null || opMode.isEmpty() || opMode.contentEquals(StringConstants.UNKNOWN_MODE)
+ ? defaultMode
+ : opMode;
+ }
+
+ private PceLink getOppPceLink(Integer pathEltNber, List<PceGraphEdge> edges,
+ Map<LinkId, PceLink> allPceLinks) {
+ return allPceLinks.get(new LinkId(edges.get(pathEltNber).link().getOppositeLink()));
+ }
+
+ private String getXpdrOpMode(String nwTpId, String vertice, int pathElement, PceNode currentNode,
+ String serviceType, CatalogUtils cu) {
+ InstanceIdentifier<TerminationPoint1> nwTpIid =
+ InstanceIdentifiers.createNetworkTerminationPoint1IIDBuilder(vertice, nwTpId);
+ String opMode = cu.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP, serviceType);