X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=pce%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Ftransportpce%2Fpce%2Fgraph%2FPostAlgoPathValidator.java;fp=pce%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Ftransportpce%2Fpce%2Fgraph%2FPostAlgoPathValidator.java;h=fe7dd48a9b772446551d08d6b800484617458918;hb=f8af92b07402b1d0f7087024d0a6d07f06089935;hp=53d45122e33f57808b5c46a65f57cf6bdb9385f3;hpb=b3d4257ba36696849b4391f39c4ae904407a72e1;p=transportpce.git diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java b/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java index 53d45122e..fe7dd48a9 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java @@ -66,7 +66,6 @@ public class PostAlgoPathValidator { @SuppressFBWarnings( value = "SF_SWITCH_FALLTHROUGH", justification = "intentional fallthrough") - public PceResult checkPath(GraphPath path, Map allPceNodes, Map allPceLinks, PceResult pceResult, PceConstraints pceHardConstraints, String serviceType) { @@ -377,6 +376,19 @@ public class PostAlgoPathValidator { OpucnTribSlotDef.getDefaultInstance(String.join(".", tribport, tsList.get(tsList.size() - 1).toString())))); } + private double checkOSNR(GraphPath path, Map allPceNodes, + Map allPceLinks, String serviceType, String direction, CatalogUtils cu) { + switch (direction) { + case StringConstants.SERVICE_DIRECTION_AZ: + return checkOSNRaz(path, allPceNodes, allPceLinks, serviceType, cu); + case StringConstants.SERVICE_DIRECTION_ZA: + return checkOSNRza(path, allPceNodes, allPceLinks, serviceType, cu); + default: + LOG.error("PostAlgoPathValidator.CheckOSNR : unsupported direction {}", direction); + return 0.0; + } + } + /** * Calculates the OSNR of a path, according to the direction (AtoZ/ZtoA), using the operational-modes Catalog. * @@ -384,14 +396,11 @@ public class PostAlgoPathValidator { * @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 path, Map allPceNodes, - Map allPceLinks, String serviceType, String direction, CatalogUtils cu) { + private double checkOSNRaz(GraphPath path, Map allPceNodes, + Map allPceLinks, String serviceType, CatalogUtils cu) { double spacing = 50.0; double calcPdl2 = 0; double calcOsnrdB = 0; @@ -401,264 +410,416 @@ public class PostAlgoPathValidator { double margin = 0; double pwrIn = -60.0; double pwrOut = -60.0; - int increment = 1; - int offsetLink = 0; boolean transponderPresent = false; - if (direction.equals(StringConstants.SERVICE_DIRECTION_ZA)) { - increment = - 1; - offsetLink = -1; - } - CatalogNodeType cnt; List vertices = path.getVertexList(); List 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 impairments = new HashMap<>(); - for (int n = 0; n < vertices.size(); n++) { - int pathElement = direction.equals(StringConstants.SERVICE_DIRECTION_AZ) ? n : vertices.size() - n - 1; + int bypassDegree = 0; + for (int pathElement = 0; pathElement < 2; pathElement++) { + bypassDegree = 0; PceNode currentNode = allPceNodes.get(new NodeId(vertices.get(pathElement))); - PceNode nextNode = - pathElement != vertices.size() - 1 && direction.equals(StringConstants.SERVICE_DIRECTION_AZ) - || pathElement != 0 && direction.equals(StringConstants.SERVICE_DIRECTION_ZA) - ? allPceNodes.get(new NodeId(vertices.get(pathElement + increment))) - : null; - LOG.debug("loop of check OSNR, n = {} Path Element = {}", n, 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 XPONDER: + LOG.debug("loop of check OSNR direction AZ: XPDR, Path Element = {}", pathElement); transponderPresent = true; - String nwTpId = - pathElement == 0 && direction.equals(StringConstants.SERVICE_DIRECTION_AZ) - || pathElement == vertices.size() - 1 - && direction.equals(StringConstants.SERVICE_DIRECTION_ZA) - ? getAppropriatePceLink((pathElement + offsetLink), edges, allPceLinks, direction) - .getSourceTP() - .getValue() - // last Xponder of the path (RX side) - : getAppropriatePceLink((pathElement - offsetLink - 1), edges, allPceLinks, direction) - .getDestTP() - .getValue(); - InstanceIdentifier nwTpIid = - InstanceIdentifiers.createNetworkTerminationPoint1IIDBuilder(vertices.get(pathElement), nwTpId); - LOG.debug("loop of check OSNR : XPDR, n = {} Path Element = {}", n, pathElement); + Map results = calcXpdrOSNR(cu, + pathElement == 0 + // First transponder on the Path (TX side) / Last Xponder of the path (RX side) + ? edges.get(pathElement).link().getSourceTP().getValue() + : edges.get(pathElement - 1).link().getDestTP().getValue(), + serviceType, currentNode, nextNode, vertices.get(pathElement), pathElement); + calcOnsrLin = results.get("calcOnsrLin"); + spacing = results.get("spacing"); + break; + case SRG: + LOG.debug("loop of check OSNR direction AZ: 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 (edges.get(pathElement).link().getlinkType() != OpenroadmLinkType.ADDLINK) { + LOG.error("Error processing Node {} for which output link {} is not an ADDLINK Type", + currentNode.getNodeId(), pathElement); + } + pwrIn = 0.0; + Map impairments = calcAddContrib( + cu, currentNode, edges.get(pathElement + 1).link(), + calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments.get("calcCd"); + calcPmd2 = impairments.get("calcPmd2"); + calcPdl2 = impairments.get("calcPdl2"); + calcOnsrLin = impairments.get("calcOnsrLin"); + pwrOut = impairments.get("pwrOut"); + LOG.debug("loop of check OSNR direction AZ: SRG, pathElement = {} link {} Pout = {}", + pathElement, pathElement + 1, pwrOut); + if (calcOnsrLin == Double.NEGATIVE_INFINITY || calcOnsrLin == 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 = 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()); + Map impairments = calcDropContrib( + cu, currentNode, pceLink, pwrOut, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments.get("calcCd"); + calcPmd2 = impairments.get("calcPmd2"); + calcPdl2 = impairments.get("calcPdl2"); + calcOnsrLin = impairments.get("calcOnsrLin"); + pwrIn = impairments.get("pwrIn"); + if (calcOnsrLin == Double.NEGATIVE_INFINITY || calcOnsrLin == 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 { - if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, nwTpIid) - .get().isPresent()) { -// If the Xponder operational mode (setOpMode Arg1) is not consistent or not declared in the topology (Network TP) -// Operational mode is retrieved from the service Type assuming it is supported by the Xponder (setOpMode Arg2) - opMode = setOpMode( - currentNode.getXponderOperationalMode( - networkTransactionService - .read(LogicalDatastoreType.CONFIGURATION, nwTpIid) - .get().get().getXpdrNetworkAttributes()), - // Operational mode is found as an attribute of the network TP - cu.getPceOperationalModeFromServiceType( - CatalogConstant.CatalogNodeType.TSP, serviceType)); - // Operational mode is retrieved from the service Type assuming it is supported - // by the Xponder - 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); + calcOsnrdB = getOsnrDbfromOnsrLin(calcOnsrLin); + LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOsnrdB); + LOG.info("Loop pathElement = {}, DROP, calcOsnrdB= {}", pathElement, 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 TSP is the last of the path - if (pathElement == vertices.size() - 1 && direction.equals(StringConstants.SERVICE_DIRECTION_AZ) - || pathElement == 0 && direction.equals(StringConstants.SERVICE_DIRECTION_ZA)) { - 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) - // Operational mode is set by default to standard opMode for ADD SRGs - adnMode = setOpMode(nextNode.getOperationalMode(), CatalogConstant.MWWRCORE); - // Operational mode is found in SRG attributes of the Node - 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 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); + Map impairments0 = calcBypassContrib( + cu, currentNode, nextNode, + edges.get(pathElement - 1).link(), edges.get(pathElement + 1).link(), + pwrOut, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments0.get("CD").doubleValue(); + calcPmd2 = impairments0.get("DGD2").doubleValue(); + calcPdl2 = impairments0.get("PDL2").doubleValue(); + calcOnsrLin = impairments0.get("ONSRLIN").doubleValue(); + //TODO rename impariments0 var and/or adapt catalog utils + pwrIn = impairments0.get("pwrIn").doubleValue(); + pwrOut = impairments0.get("pwrOut").doubleValue(); + LOG.debug( + "Loop pathElement= {}, DEGREE, calcOsnrdB= {}", 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(), calcCd, calcPmd2, 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, edges.get(vertices.size() - 2).link().getDestTP().getValue(), + serviceType, currentNode, vertices.get(vertices.size() - 1), vertices.size() - 1, + calcCd, calcPmd2, calcPdl2, calcOnsrLin); + 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()); + Map impairments = calcDropContrib( + cu, currentNode, pceLink, pwrOut, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments.get("calcCd"); + calcPmd2 = impairments.get("calcPmd2"); + calcPdl2 = impairments.get("calcPdl2"); + calcOnsrLin = impairments.get("calcOnsrLin"); + //commented out to avoid spotbug DLS_DEAD_LOCAL_STORE pwrIn = impairments.get("pwrIn"); + if (calcOnsrLin == Double.NEGATIVE_INFINITY || calcOnsrLin == 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 { + calcOsnrdB = getOsnrDbfromOnsrLin(calcOnsrLin); + LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOsnrdB); + LOG.info("Loop pathElement = {}, DROP, calcOsnrdB= {}", vertices.size() - 1, 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; + } + 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 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; + } + 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 path, Map allPceNodes, + Map allPceLinks, String serviceType, 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; + boolean transponderPresent = false; + List vertices = path.getVertexList(); + List 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; + Map results = calcXpdrOSNR(cu, + 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); + calcOnsrLin = results.get("calcOnsrLin"); + spacing = results.get("spacing"); break; case SRG: -// If the operational mode of the ADD/DROP MUX is not consistent or is not declared in the topology (Network TP) -// Operational mode is set by default to standard opMode for ADD/DROP SRGs - String srgMode = setOpMode(currentNode.getOperationalMode(), CatalogConstant.MWWRCORE); - cnt = CatalogConstant.CatalogNodeType.DROP; - LOG.debug("loop of check OSNR : SRG, n = {} Path Element = {}", n, pathElement); - if (pathElement <= 1 && direction.equals(StringConstants.SERVICE_DIRECTION_AZ) - || pathElement >= vertices.size() - 2 - && direction.equals(StringConstants.SERVICE_DIRECTION_ZA)) { - // 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); + 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); } - //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(); + pwrIn = 0.0; + + Map impairments = calcAddContrib( + cu, currentNode, getOppPceLink(pathElement - 2, edges, allPceLinks), + calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments.get("calcCd"); + calcPmd2 = impairments.get("calcPmd2"); + calcPdl2 = impairments.get("calcPdl2"); + calcOnsrLin = impairments.get("calcOnsrLin"); + pwrOut = impairments.get("pwrOut"); 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; - } + // 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); } - 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++; + 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()); + Map impairments = calcDropContrib( + cu, currentNode, pceLink, pwrOut, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments.get("calcCd"); + calcPmd2 = impairments.get("calcPmd2"); + calcPdl2 = impairments.get("calcPdl2"); + calcOnsrLin = impairments.get("calcOnsrLin"); + pwrIn = impairments.get("pwrIn"); + if (calcOnsrLin == Double.NEGATIVE_INFINITY || calcOnsrLin == 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 { + calcOsnrdB = getOsnrDbfromOnsrLin(calcOnsrLin); + LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOsnrdB); + LOG.info("Loop Path Element = {}, DROP, calcOsnrdB= {}", pathElement, 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; } - 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 declared in the topology -// Operational mode is set by default to standard opMode for Degree - degree1Mode = setOpMode(currentNode.getOperationalMode(), CatalogConstant.MWMWCORE); - // Same for next node which is the second degree of a ROADM node - degree2Mode = setOpMode(nextNode.getOperationalMode(), CatalogConstant.MWMWCORE); - // 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)); + LOG.info("loop of check OSNR direction ZA: DEGREE, Path Element = {}", pathElement); + Map impairments0 = calcBypassContrib( + cu, currentNode, nextNode, + getOppPceLink(pathElement, edges, allPceLinks), + getOppPceLink(pathElement - 2, edges, allPceLinks), + pwrOut, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments0.get("CD").doubleValue(); + calcPmd2 = impairments0.get("DGD2").doubleValue(); + calcPdl2 = impairments0.get("PDL2").doubleValue(); + calcOnsrLin = impairments0.get("ONSRLIN").doubleValue(); + //TODO rename impariments0 var and/or adapt catalog utils + pwrIn = impairments0.get("pwrIn").doubleValue(); + pwrOut = impairments0.get("pwrOut").doubleValue(); + LOG.debug("Loop Path Element = {}, DEGREE, calcOsnrdB= {}", + 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 - n++; + pathElement--; 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)); + + "{}; Pdl2 : {}; ONSRdB : {}", currentNode.getNodeId(), + nextNode.getNodeId(), calcCd, calcPmd2, 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, getOppPceLink(0, edges, allPceLinks).getDestTP().getValue(), + serviceType, currentNode, vertices.get(0), 0, calcCd, calcPmd2, calcPdl2, calcOnsrLin); + 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()); + Map impairments = calcDropContrib( + cu, currentNode, pceLink, pwrOut, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments.get("calcCd"); + calcPmd2 = impairments.get("calcPmd2"); + calcPdl2 = impairments.get("calcPdl2"); + calcOnsrLin = impairments.get("calcOnsrLin"); + //commented out to avoid spotbug DLS_DEAD_LOCAL_STORE pwrIn = impairments.get("pwrIn"); + if (calcOnsrLin == Double.NEGATIVE_INFINITY || calcOnsrLin == 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 { + calcOsnrdB = getOsnrDbfromOnsrLin(calcOnsrLin); + LOG.info("checkOSNR loop, last SRG osnr is {} dB", calcOsnrdB); + LOG.info("Loop Path Element = 0, DROP, calcOsnrdB= {}", 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; + } + 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 calcOsnrdB = {} " - + "dB and ONSR dB exterapolated from calcosnrlin = {}" - + " including non linear contributions", + + "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 " @@ -666,17 +827,12 @@ public class PostAlgoPathValidator { return 0.0; } double delta = margin - SYS_MARGIN; - LOG.info("In checkOSNR: Transponder Operational mode {} results in a residual margin of {} dB, according " + 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, delta, SYS_MARGIN); + delta, SYS_MARGIN); String validationMessage = delta >= 0 ? "VALIDATED" : "INVALIDATED"; - if (direction.equals(StringConstants.SERVICE_DIRECTION_AZ)) { - 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 {} {}", + LOG.info("- In checkOSNR: Z to A Path from {} to {} {}", vertices.get(vertices.size() - 1), vertices.get(0), validationMessage); - } return delta; } @@ -687,20 +843,176 @@ public class PostAlgoPathValidator { : opMode; } + private PceLink getOppPceLink(Integer pathEltNber, List edges, + Map allPceLinks) { + return allPceLinks.get(new LinkId(edges.get(pathEltNber).link().getOppositeLink())); + } - // Method to provide either regular link (AtoZ) or Opposite link (ZtoA) in the list of PceGraphEdges - private PceLink getAppropriatePceLink(Integer pathEltNber, List edges, - Map allPceLinks, String direction) { - if ((StringConstants.SERVICE_DIRECTION_AZ).equals(direction)) { - // Returns regular link. - return edges.get(pathEltNber).link(); + private String getXpdrOpMode(String nwTpId, String vertice, int pathElement, PceNode currentNode, + String serviceType, CatalogUtils cu) { + InstanceIdentifier nwTpIid = + InstanceIdentifiers.createNetworkTerminationPoint1IIDBuilder(vertice, nwTpId); + String opMode = cu.getPceOperationalModeFromServiceType(CatalogConstant.CatalogNodeType.TSP, serviceType); + try { + if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, nwTpIid).get().isPresent()) { + // If the operational mode of the Xponder is not consistent nor declared in the topology (Network TP) + opMode = setOpMode( + currentNode.getXponderOperationalMode( + networkTransactionService + .read(LogicalDatastoreType.CONFIGURATION, nwTpIid) + .get().get().getXpdrNetworkAttributes()), + // Operational mode is found as an attribute of the network TP + opMode); + // Operational mode is retrieved from the service Type assuming it is supported + // by the Xponder + LOG.debug( + "Transponder {} corresponding to path Element {} in the path has {} operational mode", + currentNode.getNodeId().getValue(), pathElement, opMode); + return opMode; + } + } catch (InterruptedException | ExecutionException e1) { + LOG.error("Issue accessing the XponderNetworkAttributes of {} for Transponder {}" + + " corresponding to path Element {} in the path ", + nwTpId, currentNode.getNodeId().getValue(), pathElement); } - //For Z to A direction, must return the opposite link - return allPceLinks.get(new LinkId(edges.get(pathEltNber).link().getOppositeLink())); + LOG.info("Did not succeed finding network TP {} in Configuration Datastore. Retrieve" + + " default Operational Mode {} from serviceType {}", nwTpId, opMode, serviceType); + return opMode; + } + + private double getLastXpdrMargin( + CatalogUtils cu, String nwTpId, String serviceType, PceNode currentNode, String vertice, int pathElement, + double calcCd, double calcPmd2, double calcPdl2, double calcOnsrLin) { + LOG.debug("Loop Path Element = {}, Step5.1, XPDR, tries calculating Margin, just before call", pathElement); + // 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 + double calcosnrdB = getOsnrDbfromOnsrLin(calcOnsrLin); + LOG.info("Loop Path Element = {}, XPDR, calcosnrdB= {}", pathElement, calcosnrdB); + return cu.getPceRxTspParameters( + getXpdrOpMode(nwTpId, vertice, pathElement, currentNode, serviceType, cu), + calcCd, Math.sqrt(calcPmd2), Math.sqrt(calcPdl2), calcosnrdB); + } + + private Map calcXpdrOSNR( + CatalogUtils cu, String nwTpId, String serviceType, + PceNode currentNode, PceNode nextNode, String vertice, int pathElement) { + // If the Xponder operational mode (setOpMode Arg1) is not consistent nor declared in the topology (Network TP) + // Operational mode is retrieved from the service Type assuming it is supported by the Xponder (setOpMode Arg2) + String opMode = getXpdrOpMode(nwTpId, vertice, pathElement, currentNode, serviceType, cu); + // If the operational mode of the ADD/DROP MUX is not consistent nor declared in the topology (Network TP) + // Operational mode is set by default to standard opMode for ADD SRGs + String adnMode = setOpMode(nextNode.getOperationalMode(), CatalogConstant.MWWRCORE); + double calcOnsrLin = cu.getPceTxTspParameters(opMode, adnMode); + LOG.debug( + "Transponder {} corresponding to path Element {} is connected to SRG which has {} operational mode", + currentNode.getNodeId().getValue(), pathElement, adnMode); + LOG.info("Transponder {} corresponding to path Element {} in the path has a TX OSNR of {} dB", + currentNode.getNodeId().getValue(), pathElement, getOsnrDbfromOnsrLin(calcOnsrLin)); + // Return the Tx ONSR of the Xponder which results from IB and OOB OSNR contributions + // and the spacing associated with Xponder operational mode that is needed to calculate OSNR + return Map.of( + "spacing", cu.getPceTxTspChannelSpacing(opMode), + "calcOnsrLin", calcOnsrLin); + } + + private Map calcDropContrib( + CatalogUtils cu, PceNode currentNode, PceLink pceLink, + double pwrOut, double calcCd, double calcPmd2, double calcPdl2, double calcOnsrLin, double spacing) { + //calculation of the SRG contribution for Drop + Map impairments = + calcLineDegradation(cu, pceLink, pwrOut, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + double pwrIn = impairments.get("pwrIn"); + impairments = cu.getPceRoadmAmpParameters( + CatalogConstant.CatalogNodeType.DROP, + setOpMode(currentNode.getOperationalMode(), CatalogConstant.MWWRCORE), + // If the operational mode of the ADD/DROP MUX is not consistent or not declared in the topology (Network TP) + // Operational mode is set by default to standard opMode for ADD/DROP SRGs + pwrIn, + impairments.get("calcCd").doubleValue(), + impairments.get("calcPmd2").doubleValue(), + calcPdl2, + impairments.get("calcOnsrLin").doubleValue(), + spacing); + return Map.of( + "calcCd", impairments.get("CD"), + "calcPmd2", impairments.get("DGD2"), + "calcPdl2", impairments.get("PDL2"), + "calcOnsrLin", impairments.get("ONSRLIN"), + "pwrIn", pwrIn); + } + + private Map calcAddContrib( + CatalogUtils cu, PceNode currentNode, PceLink pceLink, + double calcCd, double calcPmd2, double calcPdl2, double calcOnsrLin, double spacing) { + //calculation of the SRG contribution for Add + String srgMode = setOpMode(currentNode.getOperationalMode(), CatalogConstant.MWWRCORE); + // If the operational mode of the ADD/DROP MUX is not consistent or is not declared in the topology (Network TP) + // Operational mode is set by default to standard opMode for ADD/DROP SRGs + CatalogNodeType cnt = CatalogConstant.CatalogNodeType.ADD; + double pwrOut = cu.getPceRoadmAmpOutputPower( + cnt, srgMode, pceLink.getspanLoss(), spacing, pceLink.getpowerCorrection()); + //calculation of the SRG contribution either for Add and Drop + Map impairments = cu.getPceRoadmAmpParameters( + cnt, srgMode, 0, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + return Map.of( + "calcCd", impairments.get("CD"), + "calcPmd2", impairments.get("DGD2"), + "calcPdl2", impairments.get("PDL2"), + "calcOnsrLin", impairments.get("ONSRLIN"), + "pwrOut", pwrOut); + } + + private Map calcBypassContrib( + CatalogUtils cu, PceNode currentNode, PceNode nextNode, PceLink pceLink0, PceLink pceLink1, + double pwrOut, double calcCd, double calcPmd2, double calcPdl2, double calcOnsrLin, double spacing) { + // If the operational mode of the Degree is not consistent or declared in the topology + // Operational mode is set by default to standard opMode for Degree + String degree1Mode = setOpMode(currentNode.getOperationalMode(), CatalogConstant.MWMWCORE); + // Same for next node which is the second degree of a ROADM node + String degree2Mode = setOpMode(nextNode.getOperationalMode(), CatalogConstant.MWMWCORE); + // At that time OpenROADM provides only one spec for the ROADM nodes + if (!degree1Mode.equals(degree2Mode)) { + LOG.warn("Unsupported Hybrid ROADM configuration with Degree1 {} of {} operational mode and Degree2 " + + "{} of {} operational mode. Will by default use operational mode of Degree2", + currentNode.getNodeId(), degree1Mode, nextNode.getNodeId(), degree2Mode); + } + Map impairments = calcLineDegradation( + cu, pceLink0, pwrOut, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + calcCd = impairments.get("calcCd"); + calcPmd2 = impairments.get("calcPmd2"); + calcOnsrLin = impairments.get("calcOnsrLin"); + CatalogNodeType cnt0 = CatalogConstant.CatalogNodeType.EXPRESS; + double pwrIn = impairments.get("pwrIn"); + pwrOut = cu.getPceRoadmAmpOutputPower( + cnt0, degree2Mode, pceLink1.getspanLoss(), spacing, pceLink1.getpowerCorrection()); + // Adds to accumulated impairments the degradation associated with the Express + // path of ROADM : Degree1, express link, Degree2 + impairments = cu.getPceRoadmAmpParameters( + cnt0, degree2Mode, pwrIn, calcCd, calcPmd2, calcPdl2, calcOnsrLin, spacing); + impairments.put("pwrIn", pwrIn); + impairments.put("pwrOut", pwrOut); + return impairments; + } + //TODO these methods might be more indicated in a catalog utils refactoring + + private Map calcLineDegradation( + CatalogUtils cu, PceLink pceLink, + double pwrOut, double calcCd, double calcPmd2, double calcPdl2, double calcOnsrLin, double spacing) { + // Calculate degradation accumulated across incoming Link and add them to + // accumulated impairments + // This also includes Non Linear Contribution from the path + return Map.of( + "pwrIn", pwrOut - pceLink.getspanLoss(), + "calcCd", calcCd + pceLink.getcd(), + "calcPmd2", calcPmd2 + pceLink.getpmd2(), + "calcOnsrLin", calcOnsrLin + cu.calculateNLonsrContribution(pwrOut, pceLink.getLength(), spacing)); } private double getOsnrDbfromOnsrLin(double onsrLu) { - return (10 * Math.log10(1 / onsrLu)); + return 10 * Math.log10(1 / onsrLu); } /**