import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.jgrapht.GraphPath;
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.types.rev211210.OpenroadmLinkType;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmNodeType;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PceConstraintMode;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.SpectrumAssignment;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.SpectrumAssignmentBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev230526.TerminationPoint1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.OpenroadmLinkType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.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;
public static final Long CONST_OSNR = 1L;
public static final double SYS_MARGIN = 0;
+
private Double tpceCalculatedMargin = 0.0;
private final NetworkTransactionService networkTransactionService;
+ private final BitSet spectrumConstraint;
- public PostAlgoPathValidator(NetworkTransactionService networkTransactionService) {
+ public PostAlgoPathValidator(NetworkTransactionService networkTransactionService, BitSet spectrumConstraint) {
this.networkTransactionService = networkTransactionService;
+ this.spectrumConstraint = spectrumConstraint;
}
@SuppressWarnings("fallthrough")
@SuppressFBWarnings(
value = "SF_SWITCH_FALLTHROUGH",
justification = "intentional fallthrough")
-
public PceResult checkPath(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
Map<LinkId, PceLink> allPceLinks, PceResult pceResult, PceConstraints pceHardConstraints,
- String serviceType) {
+ String serviceType, PceConstraintMode mode) {
LOG.info("path = {}", path);
// check if the path is empty
if (path.getEdgeList().isEmpty()) {
return pceResult;
}
// Check if nodes are included in the hard constraints
- if (!checkInclude(path, pceHardConstraints)) {
+ if (!checkInclude(path, pceHardConstraints, mode)) {
pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
pceResult.setLocalCause(PceResult.LocalCause.HD_NODE_INCLUDE);
return pceResult;
}
// Check the inclusion if it is defined in the hard constraints
- private boolean checkInclude(GraphPath<String, PceGraphEdge> path, PceConstraints pceHardConstraintsInput) {
- List<ResourcePair> listToInclude = pceHardConstraintsInput.getListToInclude()
- .stream().sorted((rp1, rp2) -> rp1.getName().compareTo(rp2.getName()))
- .collect(Collectors.toList());
+ //TODO: remove this checkstyle false positive warning when the checkstyle bug will be fixed
+ @SuppressWarnings("MissingSwitchDefault")
+ private boolean checkInclude(GraphPath<String, PceGraphEdge> path, PceConstraints pceHardConstraintsInput,
+ PceConstraintMode mode) {
+ List<ResourcePair> listToInclude = pceHardConstraintsInput.getListToInclude();
if (listToInclude.isEmpty()) {
return true;
}
List<PceGraphEdge> pathEdges = path.getEdgeList();
LOG.debug(" in checkInclude vertex list: [{}]", path.getVertexList());
+ LOG.debug("listToInclude = {}", listToInclude);
List<String> listOfElementsSubNode = new ArrayList<>();
listOfElementsSubNode.add(pathEdges.get(0).link().getsourceNetworkSupNodeId());
listOfElementsSubNode.addAll(
listOfElementsSRLG.addAll(
listOfElementsBuild(pathEdges, PceConstraints.ResourceType.SRLG, pceHardConstraintsInput));
// validation: check each type for each element
- return listOfElementsSubNode.containsAll(
- listToInclude
- .stream().filter(rp -> PceConstraints.ResourceType.NODE.equals(rp.getType()))
- .map(ResourcePair::getName).collect(Collectors.toList()))
+ LOG.debug("listOfElementsSubNode = {}", listOfElementsSubNode);
+ return switch (mode) {
+ case Loose -> listOfElementsSubNode
+ .containsAll(listToInclude.stream()
+ .filter(rp -> PceConstraints.ResourceType.NODE.equals(rp.getType()))
+ .map(ResourcePair::getName).collect(Collectors.toList()));
+ case Strict -> listOfElementsSubNode
+ .equals(listToInclude.stream()
+ .filter(rp -> PceConstraints.ResourceType.NODE.equals(rp.getType()))
+ .map(ResourcePair::getName).collect(Collectors.toList()));
+ }
&& listOfElementsSRLG.containsAll(
listToInclude
.stream().filter(rp -> PceConstraints.ResourceType.SRLG.equals(rp.getType()))
private List<String> listOfElementsBuild(List<PceGraphEdge> pathEdges, PceConstraints.ResourceType type,
PceConstraints pceHardConstraints) {
- List<String> listOfElements = new ArrayList<>();
+ Set<String> listOfElements = new LinkedHashSet<>();
for (PceGraphEdge link : pathEdges) {
switch (type) {
case NODE:
LOG.debug("listOfElementsBuild unsupported resource type");
}
}
- return listOfElements;
+ return new ArrayList<>(listOfElements);
}
private Map<String, Uint16> chooseTribPort(GraphPath<String,
if (commonEdgeTpnPool.isEmpty()) {
continue;
}
- Integer startTribSlot = tribSlotMap.values().stream().findFirst().get().get(0).toJava();
+ Integer startTribSlot = tribSlotMap.values().stream().findFirst().orElseThrow().get(0).toJava();
Integer tribPort = (int) Math.ceil((double)startTribSlot / nbSlot);
for (Uint16 commonTribPort : commonEdgeTpnPool) {
if (tribPort.equals(commonTribPort.toJava())) {
private List<OpucnTribSlotDef> getMinMaxTpTs(Map<String, Uint16> tribPort, Map<String, List<Uint16>> tribSlot) {
String tribport = tribPort.values().toArray()[0].toString();
- List<Uint16> tsList = (List<Uint16>) tribSlot.values().toArray()[0];
+ @SuppressWarnings("unchecked") List<Uint16> tsList = (List<Uint16>) tribSlot.values().toArray()[0];
return new ArrayList<>(List.of(
OpucnTribSlotDef.getDefaultInstance(String.join(".", tribport, tsList.get(0).toString())),
OpucnTribSlotDef.getDefaultInstance(String.join(".", tribport, tsList.get(tsList.size() - 1).toString()))));
}
+ private double checkOSNR(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
+ Map<LinkId, PceLink> 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.
*
* @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;
+ private double checkOSNRaz(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;
- 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<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++) {
- 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<TerminationPoint1> 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()) {
-// 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);
+ calcXpdrOSNR(cu, signal,
+ 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);
+ 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);
}
- // 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));
+ signal.put("pwrIn", Double.valueOf(0));
+ calcAddContrib(cu, signal, currentNode, edges.get(pathElement + 1).link());
+ LOG.debug("loop of check OSNR direction AZ: SRG, pathElement = {} link {} Pout = {}",
+ pathElement, pathElement + 1, signal.get("pwrOut"));
+ 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 = 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:
-// 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 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);
}
- //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();
+ 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;
}
- 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;
- }
+ // 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);
}
- 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++;
+ 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;
}
- 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);
+ 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
- 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(),
+ 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");
}
}
- 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));
+ 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 "
+ 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;
}
: opMode;
}
+ private PceLink getOppPceLink(Integer pathEltNber, List<PceGraphEdge> edges,
+ Map<LinkId, PceLink> 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<PceGraphEdge> edges,
- Map<LinkId, PceLink> 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<TerminationPoint1> 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().orElseThrow().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, Map<String, Double> signal,
+ String nwTpId, String serviceType, PceNode currentNode, String vertice, int pathElement) {
+ 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 calcOnsrdB = getOsnrDbfromOnsrLin(signal.get("calcOnsrLin").doubleValue());
+ LOG.info("Loop Path Element = {}, XPDR, calcosnrdB= {}", pathElement, calcOnsrdB);
+ return cu.getPceRxTspParameters(
+ getXpdrOpMode(nwTpId, vertice, pathElement, currentNode, serviceType, cu),
+ signal.get("calcCd").doubleValue(),
+ Math.sqrt(signal.get("calcPmd2").doubleValue()),
+ Math.sqrt(signal.get("calcPdl2").doubleValue()),
+ calcOnsrdB);
+ }
+
+ private void calcXpdrOSNR(
+ CatalogUtils cu, Map<String, Double> signal, 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
+ signal.put("spacing", Double.valueOf(cu.getPceTxTspChannelSpacing(opMode)));
+ signal.put("calcOnsrLin", Double.valueOf(calcOnsrLin));
+ }
+
+ private void calcDropContrib(
+ CatalogUtils cu, Map<String, Double> signal, PceNode currentNode, PceLink pceLink) {
+ //calculation of the SRG contribution for Drop
+ calcLineDegradation(cu, signal, pceLink);
+ Map<String, Double> 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
+ signal.get("pwrIn").doubleValue(),
+ signal.get("calcCd").doubleValue(),
+ signal.get("calcPmd2").doubleValue(),
+ signal.get("calcPdl2").doubleValue(),
+ signal.get("calcOnsrLin").doubleValue(),
+ signal.get("spacing").doubleValue());
+ signal.putAll(
+ Map.of(
+ "calcCd", impairments.get("CD"),
+ "calcPmd2", impairments.get("DGD2"),
+ "calcPdl2", impairments.get("PDL2"),
+ "calcOnsrLin", impairments.get("ONSRLIN")));
+ }
+
+ private void calcAddContrib(
+ CatalogUtils cu, Map<String, Double> signal, PceNode currentNode, PceLink pceLink) {
+ //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(), signal.get("spacing").doubleValue(), pceLink.getpowerCorrection());
+ //calculation of the SRG contribution either for Add and Drop
+ Map<String, Double> impairments = cu.getPceRoadmAmpParameters(cnt, srgMode, 0,
+ signal.get("calcCd").doubleValue(), signal.get("calcPmd2").doubleValue(),
+ signal.get("calcPdl2").doubleValue(),
+ signal.get("calcOnsrLin").doubleValue(), signal.get("spacing").doubleValue());
+ signal.putAll(
+ Map.of(
+ "calcCd", impairments.get("CD"),
+ "calcPmd2", impairments.get("DGD2"),
+ "calcPdl2", impairments.get("PDL2"),
+ "calcOnsrLin", impairments.get("ONSRLIN"),
+ "pwrOut", Double.valueOf(pwrOut)));
+ }
+
+ private void calcBypassContrib(CatalogUtils cu, Map<String, Double> signal,
+ PceNode currentNode, PceNode nextNode, PceLink pceLink0, PceLink pceLink1) {
+ // 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);
+ }
+ calcLineDegradation(cu, signal, pceLink0);
+ CatalogNodeType cnt = CatalogConstant.CatalogNodeType.EXPRESS;
+ double pwrOut = cu.getPceRoadmAmpOutputPower(cnt, degree2Mode, pceLink1.getspanLoss(),
+ signal.get("spacing").doubleValue(), pceLink1.getpowerCorrection());
+ // Adds to accumulated impairments the degradation associated with the Express
+ // path of ROADM : Degree1, express link, Degree2
+ Map<String, Double> impairments = cu.getPceRoadmAmpParameters(cnt, degree2Mode,
+ signal.get("pwrIn").doubleValue(), signal.get("calcCd").doubleValue(),
+ signal.get("calcPmd2").doubleValue(), signal.get("calcPdl2").doubleValue(),
+ signal.get("calcOnsrLin").doubleValue(), signal.get("spacing").doubleValue());
+ signal.putAll(
+ Map.of(
+ "calcCd", impairments.get("CD"),
+ "calcPmd2", impairments.get("DGD2"),
+ "calcPdl2", impairments.get("PDL2"),
+ "calcOnsrLin", impairments.get("ONSRLIN"),
+ "pwrOut", Double.valueOf(pwrOut)));
+ }
+ //TODO these methods might be more indicated in a catalog utils refactoring
+
+ private void calcLineDegradation(CatalogUtils cu, Map<String, Double> signal, PceLink pceLink) {
+ // Calculate degradation accumulated across incoming Link and add them to
+ // accumulated impairments
+ // This also includes Non Linear Contribution from the path
+ signal.putAll(Map.of(
+ "pwrIn", Double.valueOf(signal.get("pwrOut").doubleValue() - pceLink.getspanLoss()),
+ "calcCd", Double.valueOf(signal.get("calcCd").doubleValue() + pceLink.getcd()),
+ "calcPmd2", Double.valueOf(signal.get("calcPmd2").doubleValue() + pceLink.getpmd2()),
+ "calcOnsrLin", Double.valueOf(
+ signal.get("calcOnsrLin").doubleValue()
+ + cu.calculateNLonsrContribution(
+ signal.get("pwrOut").doubleValue(), pceLink.getLength(), signal.get("spacing").doubleValue()))));
}
- private double getOsnrDbfromOnsrLin(double onsrLu) {
- return (10 * Math.log10(1 / onsrLu));
+ private double getOsnrDbfromOnsrLin(double osnrLu) {
+ return 10 * Math.log10(1 / osnrLu);
}
/**
BitSet result = BitSet.valueOf(freqMap);
boolean isFlexGrid = true;
LOG.debug("Processing path {} with length {}", path, path.getLength());
+ BitSet pceNodeFreqMap;
+ Set<PceNode> pceNodes = new LinkedHashSet<>();
+
for (PceGraphEdge edge : path.getEdgeList()) {
- NodeId srcNodeId = edge.link().getSourceId();
- LOG.debug("Processing source {} ", srcNodeId);
- if (allPceNodes.containsKey(srcNodeId)) {
- PceNode pceNode = allPceNodes.get(srcNodeId);
- LOG.debug("Processing PCE node {}", pceNode);
- String pceNodeVersion = pceNode.getVersion();
- NodeId pceNodeId = pceNode.getNodeId();
- BigDecimal sltWdthGran = pceNode.getSlotWidthGranularity();
- BigDecimal ctralFreqGran = pceNode.getCentralFreqGranularity();
- if (StringConstants.OPENROADM_DEVICE_VERSION_1_2_1.equals(pceNodeVersion)) {
- LOG.debug("Node {}: version is {} and slot width granularity is {} -> fixed grid mode",
- pceNodeId, pceNodeVersion, sltWdthGran);
- isFlexGrid = false;
- }
- if (sltWdthGran.setScale(0, RoundingMode.CEILING).equals(GridConstant.SLOT_WIDTH_50)
- && ctralFreqGran.setScale(0, RoundingMode.CEILING).equals(GridConstant.SLOT_WIDTH_50)) {
- LOG.debug("Node {}: version is {} with slot width granularity {} and central "
- + "frequency granularity is {} -> fixed grid mode",
- pceNodeId, pceNodeVersion, sltWdthGran, ctralFreqGran);
- isFlexGrid = false;
- }
- BitSet pceNodeFreqMap = pceNode.getBitSetData();
- LOG.debug("Pce node bitset {}", pceNodeFreqMap);
- if (pceNodeFreqMap != null) {
- result.and(pceNodeFreqMap);
- LOG.debug("intermediate bitset {}", result);
- }
+ NodeId srcId = edge.link().getSourceId();
+ NodeId dstId = edge.link().getDestId();
+ LOG.debug("Processing {} to {}", srcId.getValue(), dstId.getValue());
+ if (allPceNodes.containsKey(srcId)) {
+ pceNodes.add(allPceNodes.get(srcId));
+ }
+ if (allPceNodes.containsKey(dstId)) {
+ pceNodes.add(allPceNodes.get(dstId));
}
}
+
+ for (PceNode pceNode : pceNodes) {
+ LOG.debug("Processing PCE node {}", pceNode);
+ pceNodeFreqMap = pceNode.getBitSetData();
+ LOG.debug("Pce node bitset {}", pceNodeFreqMap);
+ if (pceNodeFreqMap != null) {
+ result.and(pceNodeFreqMap);
+ LOG.debug("intermediate bitset {}", result);
+ }
+ String pceNodeVersion = pceNode.getVersion();
+ BigDecimal sltWdthGran = pceNode.getSlotWidthGranularity();
+ if (StringConstants.OPENROADM_DEVICE_VERSION_1_2_1.equals(pceNodeVersion)) {
+ LOG.debug("Node {}: version is {} with slot width granularity {} - fixed grid mode",
+ pceNode.getNodeId(), pceNodeVersion, sltWdthGran);
+ isFlexGrid = false;
+ continue;
+ }
+ if (!sltWdthGran.setScale(0, RoundingMode.CEILING).equals(GridConstant.SLOT_WIDTH_50)) {
+ continue;
+ }
+ BigDecimal ctralFreqGran = pceNode.getCentralFreqGranularity();
+ if (!ctralFreqGran.setScale(0, RoundingMode.CEILING).equals(GridConstant.SLOT_WIDTH_50)) {
+ continue;
+ }
+ LOG.debug(
+ "Node {}: version is {} with slot width and central frequency granularities {} {} - fixed grid mode",
+ pceNode.getNodeId(), pceNodeVersion, sltWdthGran, ctralFreqGran);
+ isFlexGrid = false;
+ }
+ if (spectrumConstraint != null) {
+ result.and(spectrumConstraint);
+ }
+
LOG.debug("Bitset result {}", result);
return computeBestSpectrumAssignment(result, spectralWidthSlotNumber, isFlexGrid);
}