Fix few code issues
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / graph / PostAlgoPathValidator.java
1 /*
2  * Copyright © 2017 AT&T, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.transportpce.pce.graph;
10
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.BitSet;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import org.jgrapht.GraphPath;
20 import org.opendaylight.transportpce.common.ResponseCodes;
21 import org.opendaylight.transportpce.common.StringConstants;
22 import org.opendaylight.transportpce.common.fixedflex.GridConstant;
23 import org.opendaylight.transportpce.common.fixedflex.GridUtils;
24 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
25 import org.opendaylight.transportpce.pce.constraints.PceConstraints.ResourcePair;
26 import org.opendaylight.transportpce.pce.networkanalyzer.PceNode;
27 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.SpectrumAssignment;
29 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.SpectrumAssignmentBuilder;
30 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmLinkType;
31 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev181130.OpucnTribSlotDef;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
33 import org.opendaylight.yangtools.yang.common.Uint16;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 public class PostAlgoPathValidator {
38     /* Logging. */
39     private static final Logger LOG = LoggerFactory.getLogger(PostAlgoPathValidator.class);
40
41     private static final double MIN_OSNR_W100G = 17;
42     private static final double TRX_OSNR = 33;
43     private static final double ADD_OSNR = 30;
44     public static final Long CONST_OSNR = 1L;
45     public static final double SYS_MARGIN = 0;
46
47     @SuppressWarnings("fallthrough")
48     @SuppressFBWarnings(
49         value = "SF_SWITCH_FALLTHROUGH",
50         justification = "intentional fallthrough")
51     public PceResult checkPath(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
52         PceResult pceResult, PceConstraints pceHardConstraints, String serviceType) {
53
54         // check if the path is empty
55         if (path.getEdgeList().isEmpty()) {
56             pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
57             return pceResult;
58         }
59         int spectralWidthSlotNumber = GridConstant.SPECTRAL_WIDTH_SLOT_NUMBER_MAP
60             .getOrDefault(serviceType, GridConstant.NB_SLOTS_100G);
61         SpectrumAssignment spectrumAssignment = null;
62         //variable to deal with 1GE (Nb=1) and 10GE (Nb=10) cases
63         switch (serviceType) {
64             case StringConstants.SERVICE_TYPE_OTUC2:
65             case StringConstants.SERVICE_TYPE_OTUC3:
66             case StringConstants.SERVICE_TYPE_OTUC4:
67             case StringConstants.SERVICE_TYPE_400GE:
68                 spectralWidthSlotNumber = GridConstant.SPECTRAL_WIDTH_SLOT_NUMBER_MAP
69                     .getOrDefault(serviceType, GridConstant.NB_SLOTS_400G);
70             //fallthrough
71             case StringConstants.SERVICE_TYPE_100GE_T:
72             case StringConstants.SERVICE_TYPE_OTU4:
73                 spectrumAssignment = getSpectrumAssignment(path, allPceNodes, spectralWidthSlotNumber);
74                 pceResult.setServiceType(serviceType);
75                 if (spectrumAssignment.getBeginIndex().equals(Uint16.valueOf(0))
76                         && spectrumAssignment.getStopIndex().equals(Uint16.valueOf(0))) {
77                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
78                     pceResult.setLocalCause(PceResult.LocalCause.NO_PATH_EXISTS);
79                     return pceResult;
80                 }
81                 if (spectrumAssignment.getFlexGrid()) {
82                     LOG.info("Spectrum assignment flexgrid mode");
83                     pceResult.setResultWavelength(GridConstant.IRRELEVANT_WAVELENGTH_NUMBER);
84                 } else {
85                     LOG.info("Spectrum assignment fixedgrid mode");
86                     pceResult.setResultWavelength(
87                             GridUtils.getWaveLengthIndexFromSpectrumAssigment(spectrumAssignment.getBeginIndex()
88                                 .toJava()));
89                 }
90                 pceResult.setMinFreq(GridUtils.getStartFrequencyFromIndex(spectrumAssignment.getBeginIndex().toJava()));
91                 pceResult.setMaxFreq(GridUtils.getStopFrequencyFromIndex(spectrumAssignment.getStopIndex().toJava()));
92                 LOG.info("In PostAlgoPathValidator: spectrum assignment found {} {}", spectrumAssignment, path);
93
94                 // Check the OSNR
95                 if (!checkOSNR(path)) {
96                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
97                     pceResult.setLocalCause(PceResult.LocalCause.OUT_OF_SPEC_OSNR);
98                     return pceResult;
99                 }
100
101                 // Check if MaxLatency is defined in the hard constraints
102                 if ((pceHardConstraints.getMaxLatency() != -1)
103                         && (!checkLatency(pceHardConstraints.getMaxLatency(), path))) {
104                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
105                     pceResult.setLocalCause(PceResult.LocalCause.TOO_HIGH_LATENCY);
106                     return pceResult;
107                 }
108
109                 // Check if nodes are included in the hard constraints
110                 if (!checkInclude(path, pceHardConstraints)) {
111                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
112                     pceResult.setLocalCause(PceResult.LocalCause.HD_NODE_INCLUDE);
113                     return pceResult;
114                 }
115
116                 // TODO here other post algo validations can be added
117                 // more data can be sent to PceGraph module via PceResult structure if required
118
119                 pceResult.setRC(ResponseCodes.RESPONSE_OK);
120                 pceResult.setLocalCause(PceResult.LocalCause.NONE);
121                 break;
122             case StringConstants.SERVICE_TYPE_100GE_M:
123             case StringConstants.SERVICE_TYPE_10GE:
124             case StringConstants.SERVICE_TYPE_1GE:
125                 Map<String, Integer> tribSlotNbMap = Map.of(
126                     StringConstants.SERVICE_TYPE_100GE_M, 20,
127                     StringConstants.SERVICE_TYPE_10GE, 8,
128                     StringConstants.SERVICE_TYPE_1GE, 1);
129                 int tribSlotNb = tribSlotNbMap.get(serviceType);
130                 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
131                 pceResult.setServiceType(serviceType);
132                 Map<String, List<Uint16>> tribSlot = chooseTribSlot(path, allPceNodes, tribSlotNb);
133                 Map<String, Uint16> tribPort = chooseTribPort(path, allPceNodes, tribSlot, tribSlotNb);
134                 List<OpucnTribSlotDef> resultTribPortTribSlot = getMinMaxTpTs(tribPort, tribSlot);
135
136                 if (resultTribPortTribSlot.get(0) != null && resultTribPortTribSlot.get(1) != null) {
137                     pceResult.setResultTribPortTribSlot(resultTribPortTribSlot);
138                     pceResult.setRC(ResponseCodes.RESPONSE_OK);
139                     LOG.info("In PostAlgoPathValidator: found TribPort {} - tribSlot {} - tribSlotNb {}",
140                         tribPort, tribSlot, tribSlotNb);
141                 }
142                 break;
143             case StringConstants.SERVICE_TYPE_ODU4:
144             case StringConstants.SERVICE_TYPE_ODUC2:
145             case StringConstants.SERVICE_TYPE_ODUC3:
146             case StringConstants.SERVICE_TYPE_ODUC4:
147             case StringConstants.SERVICE_TYPE_100GE_S:
148                 pceResult.setRC(ResponseCodes.RESPONSE_OK);
149                 pceResult.setServiceType(serviceType);
150                 LOG.info("In PostAlgoPathValidator: ODU4/ODUCn path found {}", path);
151                 break;
152             default:
153                 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
154                 LOG.warn("In PostAlgoPathValidator checkPath: unsupported serviceType {} found {}",
155                     serviceType, path);
156                 break;
157         }
158         return pceResult;
159     }
160
161     // Check the latency
162     private boolean checkLatency(Long maxLatency, GraphPath<String, PceGraphEdge> path) {
163         double latency = 0;
164
165         for (PceGraphEdge edge : path.getEdgeList()) {
166             if (edge.link() == null || edge.link().getLatency() == null) {
167                 LOG.warn("- In checkLatency: the link {} does not contain latency field",
168                     edge.link().getLinkId().getValue());
169                 return false;
170             }
171             latency += edge.link().getLatency();
172             LOG.debug("- In checkLatency: latency of {} = {} units", edge.link().getLinkId().getValue(), latency);
173         }
174         return (latency < maxLatency);
175     }
176
177     // Check the inclusion if it is defined in the hard constraints
178     private boolean checkInclude(GraphPath<String, PceGraphEdge> path, PceConstraints pceHardConstraintsInput) {
179         List<ResourcePair> listToInclude = pceHardConstraintsInput.getListToInclude();
180         if (listToInclude.isEmpty()) {
181             return true;
182         }
183
184         List<PceGraphEdge> pathEdges = path.getEdgeList();
185         LOG.debug(" in checkInclude vertex list: [{}]", path.getVertexList());
186
187         List<String> listOfElementsSubNode = new ArrayList<>();
188         listOfElementsSubNode.add(pathEdges.get(0).link().getsourceNetworkSupNodeId());
189         listOfElementsSubNode.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.NODE,
190             pceHardConstraintsInput));
191
192         List<String> listOfElementsCLLI = new ArrayList<>();
193         listOfElementsCLLI.add(pathEdges.get(0).link().getsourceCLLI());
194         listOfElementsCLLI.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.CLLI,
195             pceHardConstraintsInput));
196
197         List<String> listOfElementsSRLG = new ArrayList<>();
198         // first link is XPONDEROUTPUT, no SRLG for it
199         listOfElementsSRLG.add("NONE");
200         listOfElementsSRLG.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.SRLG,
201             pceHardConstraintsInput));
202
203         // validation: check each type for each element
204         for (ResourcePair next : listToInclude) {
205             int indx = -1;
206             switch (next.getType()) {
207                 case NODE:
208                     if (listOfElementsSubNode.contains(next.getName())) {
209                         indx = listOfElementsSubNode.indexOf(next.getName());
210                     }
211                     break;
212                 case SRLG:
213                     if (listOfElementsSRLG.contains(next.getName())) {
214                         indx = listOfElementsSRLG.indexOf(next.getName());
215                     }
216                     break;
217                 case CLLI:
218                     if (listOfElementsCLLI.contains(next.getName())) {
219                         indx = listOfElementsCLLI.indexOf(next.getName());
220                     }
221                     break;
222                 default:
223                     LOG.warn(" in checkInclude vertex list unsupported resource type: [{}]", next.getType());
224             }
225
226             if (indx < 0) {
227                 LOG.debug(" in checkInclude stopped : {} ", next.getName());
228                 return false;
229             }
230
231             LOG.debug(" in checkInclude next found {} in {}", next.getName(), path.getVertexList());
232
233             listOfElementsSubNode.subList(0, indx).clear();
234             listOfElementsCLLI.subList(0, indx).clear();
235             listOfElementsSRLG.subList(0, indx).clear();
236         }
237
238         LOG.info(" in checkInclude passed : {} ", path.getVertexList());
239         return true;
240     }
241
242     private List<String> listOfElementsBuild(List<PceGraphEdge> pathEdges, PceConstraints.ResourceType type,
243         PceConstraints pceHardConstraints) {
244
245         List<String> listOfElements = new ArrayList<>();
246         for (PceGraphEdge link : pathEdges) {
247             switch (type) {
248                 case NODE:
249                     listOfElements.add(link.link().getdestNetworkSupNodeId());
250                     break;
251                 case CLLI:
252                     listOfElements.add(link.link().getdestCLLI());
253                     break;
254                 case SRLG:
255                     if (link.link().getlinkType() != OpenroadmLinkType.ROADMTOROADM) {
256                         listOfElements.add("NONE");
257                         break;
258                     }
259                     // srlg of link is List<Long>. But in this algo we need string representation of
260                     // one SRLG
261                     // this should be any SRLG mentioned in include constraints if any of them if
262                     // mentioned
263                     boolean found = false;
264                     for (Long srlg : link.link().getsrlgList()) {
265                         String srlgStr = String.valueOf(srlg);
266                         if (pceHardConstraints.getSRLGnames().contains(srlgStr)) {
267                             listOfElements.add(srlgStr);
268                             LOG.info("listOfElementsBuild. FOUND SRLG {} in link {}", srlgStr, link.link());
269                             found = true;
270                         }
271                     }
272                     if (!found) {
273                         // there is no specific srlg to include. thus add to list just the first one
274                         listOfElements.add("NONE");
275                     }
276                     break;
277                 default:
278                     LOG.debug("listOfElementsBuild unsupported resource type");
279             }
280         }
281         return listOfElements;
282     }
283
284     private Map<String, Uint16> chooseTribPort(GraphPath<String,
285         PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes, Map<String, List<Uint16>> tribSlotMap, int nbSlot) {
286         LOG.info("In choosetribPort: edgeList = {} ", path.getEdgeList());
287         Map<String, Uint16> tribPortMap = new HashMap<>();
288
289         for (PceGraphEdge edge : path.getEdgeList()) {
290             NodeId linkSrcNode = edge.link().getSourceId();
291             String linkSrcTp = edge.link().getSourceTP().getValue();
292             NodeId linkDestNode = edge.link().getDestId();
293             String linkDestTp = edge.link().getDestTP().getValue();
294             PceNode pceOtnNodeSrc = allPceNodes.get(linkSrcNode);
295             PceNode pceOtnNodeDest = allPceNodes.get(linkDestNode);
296             List<Uint16> srcTpnPool = pceOtnNodeSrc.getAvailableTribPorts().get(linkSrcTp);
297             List<Uint16> destTpnPool = pceOtnNodeDest.getAvailableTribPorts().get(linkDestTp);
298             List<Uint16> commonEdgeTpnPool = new ArrayList<>();
299             for (Uint16 srcTpn : srcTpnPool) {
300                 if (destTpnPool.contains(srcTpn)) {
301                     commonEdgeTpnPool.add(srcTpn);
302                 }
303             }
304             Collections.sort(commonEdgeTpnPool);
305             if (!commonEdgeTpnPool.isEmpty()) {
306                 Integer startTribSlot = tribSlotMap.values().stream().findFirst().get().get(0).toJava();
307                 Integer tribPort = (int) Math.ceil((double)startTribSlot / nbSlot);
308                 for (Uint16 commonTribPort : commonEdgeTpnPool) {
309                     if (tribPort.equals(commonTribPort.toJava())) {
310                         tribPortMap.put(edge.link().getLinkId().getValue(), commonTribPort);
311                     }
312                 }
313             }
314         }
315         tribPortMap.forEach((k,v) -> LOG.info("TribPortMap : k = {}, v = {}", k, v));
316         return tribPortMap;
317     }
318
319     private Map<String, List<Uint16>> chooseTribSlot(GraphPath<String,
320         PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes, int nbSlot) {
321         LOG.info("In choosetribSlot: edgeList = {} ", path.getEdgeList());
322         Map<String, List<Uint16>> tribSlotMap = new HashMap<>();
323
324         for (PceGraphEdge edge : path.getEdgeList()) {
325             NodeId linkSrcNode = edge.link().getSourceId();
326             String linkSrcTp = edge.link().getSourceTP().getValue();
327             NodeId linkDestNode = edge.link().getDestId();
328             String linkDestTp = edge.link().getDestTP().getValue();
329             PceNode pceOtnNodeSrc = allPceNodes.get(linkSrcNode);
330             PceNode pceOtnNodeDest = allPceNodes.get(linkDestNode);
331             List<Uint16> srcTsPool = pceOtnNodeSrc.getAvailableTribSlots().get(linkSrcTp);
332             List<Uint16> destTsPool = pceOtnNodeDest.getAvailableTribSlots().get(linkDestTp);
333             List<Uint16> commonEdgeTsPoolList = new ArrayList<>();
334             List<Uint16> tribSlotList = new ArrayList<>();
335             for (Uint16 integer : srcTsPool) {
336                 if (destTsPool.contains(integer)) {
337                     commonEdgeTsPoolList.add(integer);
338                 }
339             }
340             Collections.sort(commonEdgeTsPoolList);
341             List<Uint16> commonGoodStartEdgeTsPoolList = new ArrayList<>();
342             for (Uint16 startEdgeTsPool : commonEdgeTsPoolList) {
343                 if (Integer.valueOf(1).equals(startEdgeTsPool.toJava() % nbSlot)
344                         || nbSlot == 1) {
345                     commonGoodStartEdgeTsPoolList.add(startEdgeTsPool);
346                 }
347             }
348             Collections.sort(commonGoodStartEdgeTsPoolList);
349             boolean goodTsList = false;
350             for (Uint16 goodStartTsPool : commonGoodStartEdgeTsPoolList) {
351                 int goodStartIndex = commonEdgeTsPoolList.indexOf(Uint16.valueOf(goodStartTsPool.intValue()));
352                 if (!goodTsList && commonEdgeTsPoolList.size() - goodStartIndex >= nbSlot) {
353                     for (int i = 0; i < nbSlot; i++) {
354                         if (!commonEdgeTsPoolList.get(goodStartIndex + i)
355                                 .equals(Uint16.valueOf(goodStartTsPool.toJava() + i))) {
356                             goodTsList = false;
357                             tribSlotList.clear();
358                             break;
359                         }
360                         tribSlotList.add(commonEdgeTsPoolList.get(goodStartIndex + i));
361                         goodTsList = true;
362                     }
363                 }
364             }
365             tribSlotMap.put(edge.link().getLinkId().getValue(), tribSlotList);
366         }
367         tribSlotMap.forEach((k,v) -> LOG.info("TribSlotMap : k = {}, v = {}", k, v));
368         return tribSlotMap;
369     }
370
371     private List<OpucnTribSlotDef> getMinMaxTpTs(Map<String, Uint16> tribPort, Map<String, List<Uint16>> tribSlot) {
372         String tribport = tribPort.values().toArray()[0].toString();
373         @SuppressWarnings("unchecked")
374         List<Uint16> tsList = (List<Uint16>) tribSlot.values().toArray()[0];
375         OpucnTribSlotDef minOpucnTs = OpucnTribSlotDef
376             .getDefaultInstance(String.join(".", tribport, tsList.get(0).toString()));
377         OpucnTribSlotDef maxOpucnTs = OpucnTribSlotDef
378             .getDefaultInstance(String.join(".", tribport, tsList.get(tsList.size() - 1).toString()));
379         List<OpucnTribSlotDef> minmaxTpTsList = new ArrayList<>();
380         minmaxTpTsList.add(minOpucnTs);
381         minmaxTpTsList.add(maxOpucnTs);
382         return minmaxTpTsList;
383     }
384
385     // Check the path OSNR
386     private boolean checkOSNR(GraphPath<String, PceGraphEdge> path) {
387         double linkOsnrDb;
388         double osnrDb = 0;
389         LOG.info("- In checkOSNR: OSNR of the transmitter = {} dB", TRX_OSNR);
390         LOG.info("- In checkOSNR: add-path incremental OSNR = {} dB", ADD_OSNR);
391         double inverseLocalOsnr = getInverseOsnrLinkLu(TRX_OSNR) + getInverseOsnrLinkLu(ADD_OSNR);
392         for (PceGraphEdge edge : path.getEdgeList()) {
393             if (edge.link().getlinkType() == OpenroadmLinkType.ROADMTOROADM) {
394                 // link OSNR in dB
395                 linkOsnrDb = edge.link().getosnr();
396                 LOG.info("- In checkOSNR: OSNR of {} = {} dB", edge.link().getLinkId().getValue(), linkOsnrDb);
397                 // 1 over the local OSNR, in linear units
398                 inverseLocalOsnr += getInverseOsnrLinkLu(linkOsnrDb);
399             }
400         }
401         try {
402             osnrDb = getOsnrDb(1 / inverseLocalOsnr);
403         } catch (ArithmeticException e) {
404             LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}", path.getEdgeList().size());
405             return false;
406         }
407         LOG.info("In checkOSNR: OSNR of the path is {} dB", osnrDb);
408         return ((osnrDb + SYS_MARGIN) > MIN_OSNR_W100G);
409     }
410
411     private double getOsnrDb(double osnrLu) {
412         return (10 * Math.log10(osnrLu));
413     }
414
415     private double getInverseOsnrLinkLu(double linkOsnrDb) {
416         // 1 over the link OSNR, in linear units
417         double linkOsnrLu = Math.pow(10, (linkOsnrDb / 10.0));
418         LOG.debug("In retrieveosnr: the inverse of link osnr is {} (Linear Unit)", linkOsnrLu);
419         return (CONST_OSNR / linkOsnrLu);
420     }
421
422     /**
423      * Get spectrum assignment for path.
424      *
425      * @param path                    the path for which we get spectrum assignment.
426      * @param allPceNodes             all optical nodes.
427      * @param spectralWidthSlotNumber number of slot for spectral width. Depends on
428      *                                service type.
429      * @return a spectrum assignment object which contains begin and end index. If
430      *         no spectrum assignment found, beginIndex = stopIndex = 0
431      */
432     private SpectrumAssignment getSpectrumAssignment(GraphPath<String, PceGraphEdge> path,
433             Map<NodeId, PceNode> allPceNodes, int spectralWidthSlotNumber) {
434         byte[] freqMap = new byte[GridConstant.NB_OCTECTS];
435         Arrays.fill(freqMap, (byte) GridConstant.AVAILABLE_SLOT_VALUE);
436         BitSet result = BitSet.valueOf(freqMap);
437         boolean isFlexGrid = true;
438         LOG.info("Processing path {} with length {}", path, path.getLength());
439         BitSet pceNodeFreqMap;
440         for (PceGraphEdge edge : path.getEdgeList()) {
441             LOG.info("Processing source {} ", edge.link().getSourceId());
442             if (allPceNodes.containsKey(edge.link().getSourceId())) {
443                 PceNode pceNode = allPceNodes.get(edge.link().getSourceId());
444                 LOG.info("Processing PCE node {}", pceNode);
445                 if (StringConstants.OPENROADM_DEVICE_VERSION_1_2_1.equals(pceNode.getVersion())) {
446                     LOG.info("Node {}: version is {} and slot width granularity is {} -> fixed grid mode",
447                         pceNode.getNodeId(), pceNode.getVersion(), pceNode.getSlotWidthGranularity());
448                     isFlexGrid = false;
449                 }
450                 if ((pceNode.getSlotWidthGranularity().equals(GridConstant.SLOT_WIDTH_50))
451                     && (pceNode.getCentralFreqGranularity().equals(GridConstant.SLOT_WIDTH_50))) {
452                     LOG.info("Node {}: version is {} with slot width granularity  {} and central "
453                             + "frequency granularity is {} -> fixed grid mode",
454                         pceNode.getNodeId(), pceNode.getVersion(), pceNode.getSlotWidthGranularity(),
455                         pceNode.getCentralFreqGranularity());
456                     isFlexGrid = false;
457                 }
458                 pceNodeFreqMap = pceNode.getBitSetData();
459                 LOG.debug("Pce node bitset {}", pceNodeFreqMap);
460                 if (pceNodeFreqMap != null) {
461                     result.and(pceNodeFreqMap);
462                     LOG.debug("intermediate bitset {}", result);
463                 }
464             }
465         }
466         LOG.debug("Bitset result {}", result);
467         return computeBestSpectrumAssignment(result, spectralWidthSlotNumber, isFlexGrid);
468     }
469
470     /**
471      * Compute spectrum assignment from spectrum occupation for spectral width.
472      *
473      * @param spectrumOccupation      the spectrum occupation BitSet.
474      * @param spectralWidthSlotNumber the nb slots for spectral width.
475      * @param isFlexGrid              true if flexible grid, false otherwise.
476      * @return a spectrum assignment object which contains begin and stop index. If
477      *         no spectrum assignment found, beginIndex = stopIndex = 0
478      */
479     private SpectrumAssignment computeBestSpectrumAssignment(BitSet spectrumOccupation, int spectralWidthSlotNumber,
480             boolean isFlexGrid) {
481         SpectrumAssignmentBuilder spectrumAssignmentBldr = new SpectrumAssignmentBuilder()
482             .setBeginIndex(Uint16.valueOf(0))
483             .setStopIndex(Uint16.valueOf(0))
484             .setFlexGrid(isFlexGrid);
485         BitSet referenceBitSet = new BitSet(spectralWidthSlotNumber);
486         referenceBitSet.set(0, spectralWidthSlotNumber);
487         int nbSteps = isFlexGrid ? spectralWidthSlotNumber : 1;
488         //higher is the frequency, smallest is the wavelength number
489         //in operational, the allocation is done through wavelength starting from the smallest
490         //so we have to loop from the last element of the spectrum occupation
491         for (int i = spectrumOccupation.size(); i >= spectralWidthSlotNumber; i -= nbSteps) {
492             if (spectrumOccupation.get(i - spectralWidthSlotNumber, i).equals(referenceBitSet)) {
493                 spectrumAssignmentBldr.setBeginIndex(Uint16.valueOf(i - spectralWidthSlotNumber));
494                 spectrumAssignmentBldr.setStopIndex(Uint16.valueOf(i - 1));
495                 break;
496             }
497         }
498         return spectrumAssignmentBldr.build();
499     }
500 }