001package com.net2plan.examples.general.onlineSim; 002/******************************************************************************* 003 * Copyright (c) 2017 Pablo Pavon Marino and others. 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the 2-clause BSD License 006 * which accompanies this distribution, and is available at 007 * https://opensource.org/licenses/BSD-2-Clause 008 * 009 * Contributors: 010 * Pablo Pavon Marino and others - initial API and implementation 011 *******************************************************************************/ 012 013 014import java.util.ArrayList; 015import java.util.HashMap; 016import java.util.HashSet; 017import java.util.List; 018import java.util.Map; 019import java.util.Random; 020import java.util.Set; 021import java.util.stream.Collectors; 022 023import com.net2plan.interfaces.networkDesign.Demand; 024import com.net2plan.interfaces.networkDesign.Link; 025import com.net2plan.interfaces.networkDesign.Net2PlanException; 026import com.net2plan.interfaces.networkDesign.NetPlan; 027import com.net2plan.interfaces.networkDesign.NetworkElement; 028import com.net2plan.interfaces.networkDesign.NetworkLayer; 029import com.net2plan.interfaces.networkDesign.Node; 030import com.net2plan.interfaces.networkDesign.Route; 031import com.net2plan.interfaces.networkDesign.SharedRiskGroup; 032import com.net2plan.interfaces.simulation.IEventProcessor; 033import com.net2plan.interfaces.simulation.SimEvent; 034import com.net2plan.libraries.GraphUtils; 035import com.net2plan.libraries.SRGUtils; 036import com.net2plan.libraries.WDMUtils; 037import com.net2plan.libraries.WDMUtils.TransponderTypesInfo; 038import com.net2plan.utils.Constants.RoutingType; 039import com.net2plan.utils.InputParameter; 040import com.net2plan.utils.Pair; 041import com.net2plan.utils.Quadruple; 042import com.net2plan.utils.RandomUtils; 043import com.net2plan.utils.Triple; 044 045import cern.colt.matrix.tdouble.DoubleMatrix2D; 046import cern.jet.math.tdouble.DoubleFunctions; 047 048/** Implements the reactions of a WDM network carrying lightpaths in a fixed or flexi grid of wavelengths. 049 * 050 * <p>The design follows the assumptions described in {@link com.net2plan.libraries.WDMUtils WDMUtils} Net2Plan library</p> 051 * <p>This algorithm implements the reactions of a WDM network carrying lightpaths, to the following events:</p> 052 * <ul> 053 * <li>{@link com.net2plan.libraries.WDMUtils.LightpathAdd WDMUtils.LightpathAdd}: Adds the corresponding lightpath to the network 054 * (the Route object and potentially a ProtectionSegment object if the lightpath is asked to be 1+1 protected), 055 * if enough resources exist for it. If the event includes a Demand object, the lightpath is associated to it. 056 * If not, a new demand is created. The object establishes the line rate of the lightpath to establish. If such line rate is 057 * not present in any transponder type defined, an exception is raised (on valid transponders exist for such a lightpath). 058 * If the event includes the RSA (also of the backup, if 1+1 protection is selected), the algorithm 059 * tries this RSA. If not, the user-selected strategy for the routing and spectrum assignment of the lightpath is applied. 060 * Such strategy is tried first with the first transponder type (in order) with the appropriate line rate. If a valid RSA is not found 061 * it is repeated with the next. The lightpath request is blocked if under no transponder type of the appropriate line rate, a RSA 062 * is found (note that different transponders can have e.g. different optical reaches or number of occupied slots).</li> 063 * <li>{@link com.net2plan.libraries.WDMUtils.LightpathModify WDMUtils.LightpathModify}: Modifies the carried traffic and/or the RSA of a lightpath.</li> 064 * <li>{@link com.net2plan.libraries.WDMUtils.LightpathRemove WDMUtils.LightpathRemove}: Removes the corresponding lightpath (including the Demand and Route objects, and potentially the 1+1 segment if any), releasing the resources.</li> 065 * <li>{@link com.net2plan.interfaces.simulation.SimEvent.NodesAndLinksChangeFailureState SimEvent.NodesAndLinksChangeFailureState}: Fails/repairs the indicated nodes and/or links, and reacts to such failures 066 * (the particular form depends on the network recovery options selected).</li> 067 * <li>{@link com.net2plan.interfaces.simulation.SimEvent.DemandModify SimEvent.DemandModify}: Modifies the offered traffic of a demand.</li> 068 * <li>{@link com.net2plan.interfaces.simulation.SimEvent.DemandRemove SimEvent.DemandRemove}: Removes a demand, and all its associated lightpaths if any, releasing the resources.</li> 069 * </ul> 070 * 071 * This module can be used in conjunction with the {@code Online_evGen_wdm} generator for creating the events to which 072 * this module reacts. 073 * 074 * See in {@link com.net2plan.libraries.WDMUtils} Javadoc the WDM technology conventions used in Net2Plan built-in algorithms and libraries to represent WDM networks. 075 * @net2plan.keywords WDM, Network recovery: protection, Network recovery: restoration 076 * @net2plan.inputParameters 077 */ 078public class Online_evProc_wdm extends IEventProcessor 079{ 080 private InputParameter wdmNumFrequencySlotsPerFiber = new InputParameter ("wdmNumFrequencySlotsPerFiber", (int) 40 , "Set the number of frequency slots per fiber. If < 1, the number of slots set in the input file is used."); 081 private InputParameter wdmRwaType = new InputParameter ("wdmRwaType", "#select# srg-disjointness-aware-route-first-fit alternate-routing least-congested-routing load-sharing" , "Criteria to decide the route of a connection among the available paths"); 082 private InputParameter wdmK = new InputParameter ("wdmK", (int) 5 , "Maximum number of admissible paths per demand in the candidate list computation" , 1 , Integer.MAX_VALUE); 083 private InputParameter wdmRandomSeed = new InputParameter ("wdmRandomSeed", (long) 1 , "Seed for the random generator (-1 means random)"); 084 private InputParameter wdmMaxLightpathNumHops = new InputParameter ("wdmMaxLightpathNumHops", (int) -1 , "A lightpath cannot have more than this number of hops. A non-positive number means this limit does not exist"); 085// private InputParameter wdmRecoveryType = new InputParameter ("wdmRecoveryType", "#select# protection restoration none" , "None, nothing is done, so affected routes fail. Restoration, affected routes are visited sequentially, and we try to reroute them in the available capacity; in protection, affected routes are rerouted using the protection segments."); 086 private InputParameter wdmRemovePreviousLightpaths = new InputParameter ("wdmRemovePreviousLightpaths", false , "If true, previous lightpaths are removed from the system during initialization."); 087 //private InputParameter wdmProtectionTypeToNewRoutes = new InputParameter ("wdmProtectionTypeToNewRoutes", "#select# none 1+1-link-disjoint 1+1-node-disjoint 1+1-srg-disjoint" , "New lightpaths are not protected, or are protected by a 1+1 link disjoint, or a node disjoint or a SRG disjoint lightpath"); 088 private InputParameter wdmDefaultAndNewRouteRevoveryType = new InputParameter ("wdmDefaultAndNewRouteRevoveryType", "#select# none restoration 1+1-link-disjoint 1+1-node-disjoint 1+1-srg-disjoint" , "New lightpaths are not protected, or are protected by a 1+1 link disjoint, or a node disjoint or a SRG disjoint lightpath"); 089 private InputParameter wdmTransponderTypesInfo = new InputParameter ("wdmTransponderTypesInfo", "10 1 1 9600 1" , "Transpoder types separated by \";\" . Each type is characterized by the space-separated values: (i) Line rate in Gbps, (ii) cost of the transponder, (iii) number of slots occupied in each traversed fiber, (iv) optical reach in km (a non-positive number means no reach limit), (v) cost of the optical signal regenerator (regenerators do NOT make wavelength conversion ; if negative, regeneration is not possible)."); 090 091 private NetworkLayer wdmLayer; 092 //private Map<Route,Pair<WDMUtils.RSA,WDMUtils.RSA>> wdmRouteOriginalRwa; 093 private Map<Pair<Node,Node>,List<List<Link>>> cplWdm; 094 private Map<Pair<Node,Node>,List<Pair<List<Link>,List<Link>>>> cplWdm11; 095 private DoubleMatrix2D wavelengthFiberOccupancy; 096 private TransponderTypesInfo tpInfo; 097 private Map<Route,Integer> transponderTypeOfNewLps; 098 099// private boolean newRoutesHave11Protection; 100 private boolean isRestorationRecovery , isProtectionRecovery; 101 private boolean isAlternateRouting , isLeastCongestedRouting , isLoadSharing , isSrgDisjointAwareLpRouting; 102 private Random rng; 103 private int protectionTypeCode; 104 private Demand.IntendedRecoveryType defaultRecoveryType; 105 106 private double stat_trafficOfferedConnections , stat_trafficCarriedConnections; 107 private double stat_trafficAttemptedToRecoverConnections , stat_trafficSuccessfullyRecoveredConnections; 108 private long stat_numOfferedConnections , stat_numCarriedConnections; 109 private long stat_numAttemptedToRecoverConnections , stat_numSuccessfullyRecoveredConnections; 110 private double stat_transitoryInitTime; 111 public boolean DEBUG = false; 112 113 @Override 114 public String getDescription() 115 { 116 return "Implements the reactions of a WDM network carrying lightpaths in a fixed grid of wavelengths"; 117 } 118 119 @Override 120 public List<Triple<String, String, String>> getParameters() 121 { 122 /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */ 123 return InputParameter.getInformationAllInputParameterFieldsOfObject(this); 124 } 125 126 @Override 127 public void initialize(NetPlan initialNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters) 128 { 129 /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */ 130 InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters); 131 132 this.wdmLayer = initialNetPlan.getNetworkLayer("WDM"); if (wdmLayer == null) throw new Net2PlanException ("WDM layer not found"); 133 this.isRestorationRecovery = wdmDefaultAndNewRouteRevoveryType.getString ().equalsIgnoreCase("restoration"); 134 this.isProtectionRecovery = wdmDefaultAndNewRouteRevoveryType.getString ().startsWith("1+1"); 135 this.isAlternateRouting = wdmRwaType.getString().equalsIgnoreCase("alternate-routing"); 136 this.isLeastCongestedRouting = wdmRwaType.getString().equalsIgnoreCase("least-congested-routing"); 137 this.isSrgDisjointAwareLpRouting = wdmRwaType.getString().equalsIgnoreCase("srg-disjointness-aware-route-first-fit");; 138 this.isLoadSharing = wdmRwaType.getString().equalsIgnoreCase("load-sharing"); 139 this.rng = new Random(wdmRandomSeed.getLong () == -1? (long) RandomUtils.random(0, Long.MAX_VALUE - 1) : wdmRandomSeed.getLong ()); 140 141 this.defaultRecoveryType = isProtectionRecovery? Demand.IntendedRecoveryType.PROTECTION_REVERT : isRestorationRecovery? Demand.IntendedRecoveryType.RESTORATION : Demand.IntendedRecoveryType.NONE; 142 143 if (wdmRemovePreviousLightpaths.getBoolean()) 144 { 145 initialNetPlan.removeAllRoutes(wdmLayer); 146 initialNetPlan.removeAllMulticastTrees(wdmLayer); 147 } 148 if (wdmNumFrequencySlotsPerFiber.getInt() > 0) WDMUtils.setFibersNumFrequencySlots(initialNetPlan , wdmNumFrequencySlotsPerFiber.getInt() , wdmLayer); 149 150 /* Get the transponders information */ 151 this.tpInfo = new TransponderTypesInfo(wdmTransponderTypesInfo.getString()); 152 this.transponderTypeOfNewLps = new HashMap<Route,Integer> (); 153 154 /* Create empty candidate path lists: they will be filled on demand */ 155 this.cplWdm = new HashMap<> (); 156 this.protectionTypeCode = wdmDefaultAndNewRouteRevoveryType.getString ().equals("1+1-srg-disjoint") ? 0 : wdmDefaultAndNewRouteRevoveryType.getString ().equals("1+1-node-disjoint")? 1 : 2; 157 this.cplWdm11 = isProtectionRecovery? new HashMap<> () : null; 158 159 this.wavelengthFiberOccupancy = WDMUtils.getNetworkSlotAndRegeneratorOcupancy(initialNetPlan, true , wdmLayer).getFirst(); 160 if (DEBUG) { checkWaveOccupEqualsNp(initialNetPlan); checkClashing (initialNetPlan); } 161 initialNetPlan.setLinkCapacityUnitsName("Frequency slots" , wdmLayer); 162 163 this.finishTransitory(0); 164 if (DEBUG) { checkWaveOccupEqualsNp(initialNetPlan); checkClashing (initialNetPlan); } 165 } 166 167 @Override 168 public void processEvent(NetPlan currentNetPlan, SimEvent event) 169 { 170 try { 171 if (event.getEventObject () instanceof WDMUtils.LightpathAdd) 172 { 173 WDMUtils.LightpathAdd addLpEvent = (WDMUtils.LightpathAdd) event.getEventObject (); 174 if (addLpEvent.layer != this.wdmLayer) throw new Net2PlanException ("Lightpaths cannot be added to layer " + addLpEvent.demand.getLayer() + ", and just to the WDM layer (" + wdmLayer + ")"); 175 final Node ingressNode = addLpEvent.ingressNode; 176 final Node egressNode = addLpEvent.egressNode; 177 final Pair<Node,Node> cplNodePair = Pair.of(ingressNode,egressNode); 178 final double lineRateThisLp_Gbps = addLpEvent.lineRateGbps; 179 if (!tpInfo.isValidLineRateForAtLeastOneType (lineRateThisLp_Gbps)) throw new Net2PlanException ("Requested to set up a lightpath of a line rate (" + lineRateThisLp_Gbps + ") for which I don't have transpoders"); 180 181 /* update the offered traffic of the demand */ 182 this.stat_numOfferedConnections ++; 183 this.stat_trafficOfferedConnections += lineRateThisLp_Gbps; 184 185 /* Computes one or two paths over the links (the second path would be a segment). You cannot use the already existing segments in these paths */ 186 if (isProtectionRecovery) 187 { 188 /* The RWA may be computed by me, or mandated by the event */ 189 Pair<WDMUtils.RSA,WDMUtils.RSA> rwa = null; 190 int transponderTypeUsed = -1; 191 if ((addLpEvent.primaryRSA != null) && (addLpEvent.backupRSA != null)) 192 { 193 if (!WDMUtils.isAllocatableRSASet(wavelengthFiberOccupancy , addLpEvent.primaryRSA , addLpEvent.backupRSA)) 194 throw new Net2PlanException ("A request was received to add a conflicting lightpath 1+1 pair"); 195 rwa = Pair.of (addLpEvent.primaryRSA , addLpEvent.backupRSA); 196 } 197 else 198 { 199 /* Check among the transponder types (in order), the one in the same rate that fits (optical reach in range). */ 200 for (int t = 0; t < tpInfo.getNumTypes() ; t ++) 201 { 202 if (lineRateThisLp_Gbps != tpInfo.getLineRateGbps(t)) continue; 203 rwa = computeValid11PathPairNewRoute(cplNodePair , currentNetPlan , tpInfo.getNumSlots(t) , tpInfo.getOpticalReachKm(t) , tpInfo.isOpticalRegenerationPossible(t)); 204 if (rwa != null) { transponderTypeUsed = t; break; } 205 } 206 } 207 208 if (rwa != null) 209 { 210 if (!WDMUtils.isAllocatableRSASet(wavelengthFiberOccupancy , rwa.getFirst() , rwa.getSecond())) throw new RuntimeException ("Bad"); 211 if (!WDMUtils.isAllocatableRSASet(wavelengthFiberOccupancy , rwa.getSecond())) throw new RuntimeException ("Bad"); 212 for (Link e : rwa.getFirst ().seqLinks) if (e.getNetPlan() != currentNetPlan) throw new RuntimeException ("Bad. e.getNetPlan is null?: " + (e.getNetPlan() ==null) + ", currentNp is null: " + (currentNetPlan == null)); 213 for (Link e : rwa.getSecond ().seqLinks) if (e.getNetPlan() != currentNetPlan) throw new RuntimeException ("Bad"); 214 215 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 216 217 final Demand wdmLayerDemand = addLpEvent.demand == null? currentNetPlan.addDemand(addLpEvent.ingressNode, addLpEvent.egressNode, lineRateThisLp_Gbps , RoutingType.SOURCE_ROUTING , null, wdmLayer) : addLpEvent.demand; 218 wdmLayerDemand.setIntendedRecoveryType(Demand.IntendedRecoveryType.PROTECTION_REVERT); 219 final Route wdmLayerRoute = WDMUtils.addLightpath(wdmLayerDemand, rwa.getFirst(), lineRateThisLp_Gbps); 220 WDMUtils.allocateResources(rwa.getFirst() , wavelengthFiberOccupancy , null); 221 222 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 223 224 if (rwa.getFirst().seqLinks.equals(rwa.getSecond().seqLinks)) throw new RuntimeException ("Both 1+1 same route"); 225 final Route wdmLayerBackupRoute = WDMUtils.addLightpath(wdmLayerDemand, rwa.getSecond(), 0); // it is a backup, has no traffic carried then 226 wdmLayerRoute.addBackupRoute(wdmLayerBackupRoute); 227 WDMUtils.allocateResources(rwa.getSecond() , wavelengthFiberOccupancy , null); 228 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 229 checkDisjointness(wdmLayerRoute.getSeqLinks() , rwa.getSecond().seqLinks , protectionTypeCode); 230 this.transponderTypeOfNewLps.put(wdmLayerRoute , transponderTypeUsed); 231 this.stat_numCarriedConnections ++; 232 this.stat_trafficCarriedConnections += lineRateThisLp_Gbps; 233 addLpEvent.lpAddedToFillByProcessor = wdmLayerRoute; 234 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 235 } 236 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 237 } 238 else 239 { 240 /* The RWA may be computed by me, or mandated by the event */ 241 WDMUtils.RSA rwa = null; 242 int transponderTypeUsed = -1; 243 if (addLpEvent.primaryRSA != null) 244 { 245 if (!WDMUtils.isAllocatableRSASet(wavelengthFiberOccupancy , addLpEvent.primaryRSA)) 246 throw new Net2PlanException ("A request was received to add a conflicting lightpath"); 247 rwa = addLpEvent.primaryRSA; 248 } 249 else 250 { 251 /* Check among the transponder types (in order), the one in the same rate that fits (optical reach in range). */ 252 for (int t = 0; t < tpInfo.getNumTypes() ; t ++) 253 { 254 if (lineRateThisLp_Gbps != tpInfo.getLineRateGbps(t)) continue; 255 rwa = computeValidPathNewRoute(cplNodePair , currentNetPlan , tpInfo.getNumSlots(t) , tpInfo.getOpticalReachKm(t) , tpInfo.isOpticalRegenerationPossible(t)); 256 if (rwa != null) { transponderTypeUsed = t; break; } 257 } 258 } 259 if (rwa != null) 260 { 261 final Demand wdmLayerDemand = addLpEvent.demand == null? currentNetPlan.addDemand(addLpEvent.ingressNode, addLpEvent.egressNode, lineRateThisLp_Gbps , RoutingType.SOURCE_ROUTING , null, wdmLayer) : addLpEvent.demand; 262 wdmLayerDemand.setIntendedRecoveryType(isRestorationRecovery? Demand.IntendedRecoveryType.RESTORATION : Demand.IntendedRecoveryType.NONE); 263 final Route wdmLayerRoute = WDMUtils.addLightpath(wdmLayerDemand, rwa , lineRateThisLp_Gbps); 264 WDMUtils.allocateResources(rwa , wavelengthFiberOccupancy , null); 265 this.transponderTypeOfNewLps.put(wdmLayerRoute , transponderTypeUsed); 266 this.stat_numCarriedConnections ++; 267 this.stat_trafficCarriedConnections += lineRateThisLp_Gbps; 268 addLpEvent.lpAddedToFillByProcessor = wdmLayerRoute; 269 } 270 } 271 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 272 } 273 else if (event.getEventObject () instanceof WDMUtils.LightpathRemove) 274 { 275 WDMUtils.LightpathRemove lpEvent = (WDMUtils.LightpathRemove) event.getEventObject (); 276 final Route lpToRemove = lpEvent.lp; 277 WDMUtils.releaseResources(new WDMUtils.RSA(lpToRemove , false) , wavelengthFiberOccupancy, null); 278 for (Route backupLp : new ArrayList<> (lpToRemove.getBackupRoutes())) 279 { 280 WDMUtils.releaseResources(new WDMUtils.RSA(backupLp , false), wavelengthFiberOccupancy, null); 281 backupLp.remove(); 282 this.transponderTypeOfNewLps.remove(backupLp); 283 } 284 lpToRemove.remove (); 285 this.transponderTypeOfNewLps.remove(lpToRemove); 286 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 287 } else if (event.getEventObject () instanceof SimEvent.NodesAndLinksChangeFailureState) 288 { 289 SimEvent.NodesAndLinksChangeFailureState ev = (SimEvent.NodesAndLinksChangeFailureState) event.getEventObject (); 290 291 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 292 293 /* This automatically sets as up the routes affected by a repair in its current path, and sets as down the affected by a failure in its current path */ 294 Set<Route> routesFromDownToUp = new HashSet<> (currentNetPlan.getRoutesDown(wdmLayer)); 295 currentNetPlan.setLinksAndNodesFailureState(ev.linksToUp , ev.linksToDown , ev.nodesToUp , ev.nodesToDown); 296 routesFromDownToUp.removeAll(currentNetPlan.getRoutesDown(wdmLayer)); 297 298 /* If primary GOES up in PROTECTION-REVERT => backup carried is set to zero in all backups */ 299 for (Route r : routesFromDownToUp) 300 { 301 final Demand wdmDemand = r.getDemand(); 302 final Demand.IntendedRecoveryType recoveryType = wdmDemand.getIntendedRecoveryType() == Demand.IntendedRecoveryType.NOTSPECIFIED? defaultRecoveryType : wdmDemand.getIntendedRecoveryType(); 303 if (recoveryType == Demand.IntendedRecoveryType.PROTECTION_REVERT) 304 for (Route backup : r.getBackupRoutes()) 305 backup.setCarriedTraffic(0, null); // primary to up => carried in backup to zero 306 } 307 308 /* Now take down routes one by one, and see what to do with them (if something) */ 309 for (Route r : new ArrayList<> (currentNetPlan.getRoutesDown(wdmLayer))) 310 { 311 final Demand wdmDemand = r.getDemand(); 312 final Demand.IntendedRecoveryType recovType = wdmDemand.getIntendedRecoveryType() == Demand.IntendedRecoveryType.NOTSPECIFIED? defaultRecoveryType : wdmDemand.getIntendedRecoveryType(); 313 314 if (recovType == Demand.IntendedRecoveryType.NONE) continue; 315 316 if (recovType == Demand.IntendedRecoveryType.PROTECTION_REVERT) 317 { 318 /* If is 1+1 protection, do nothing with backup routes that are down */ 319 if (r.isBackupRoute()) continue; 320 this.stat_numAttemptedToRecoverConnections ++; 321 this.stat_trafficAttemptedToRecoverConnections += r.getCarriedTrafficInNoFailureState(); 322 /* The primary routes goes down => its backup has now carried traffic (if no failure) */ 323 if (r.hasBackupRoutes()) 324 { 325 final Route backupRoute = r.getBackupRoutes().get(0); 326 backupRoute.setCarriedTraffic(r.getCarriedTrafficInNoFailureState(), null); 327 if (!backupRoute.isDown()) 328 { 329 this.stat_numSuccessfullyRecoveredConnections ++; 330 this.stat_trafficSuccessfullyRecoveredConnections += r.getCarriedTrafficInNoFailureState(); 331 } 332 } 333 } 334 else if (recovType == Demand.IntendedRecoveryType.RESTORATION) 335 { 336 this.stat_numAttemptedToRecoverConnections ++; 337 this.stat_trafficAttemptedToRecoverConnections += r.getCarriedTrafficInNoFailureState(); 338 final Pair<Node,Node> cplNodePair= Pair.of(r.getIngressNode() , r.getEgressNode()); 339 final Integer transponderTypeLp = transponderTypeOfNewLps.get(r); 340 final double maxOpticalReachKm = transponderTypeLp == null? Double.MAX_VALUE : tpInfo.getOpticalReachKm(transponderTypeLp); 341 final boolean isSignalRegenerationPossible = transponderTypeLp == null? true : tpInfo.isOpticalRegenerationPossible(transponderTypeLp); 342 final int numSlots = transponderTypeLp == null? new WDMUtils.RSA(r,false).getNumSlots() : tpInfo.getNumSlots(transponderTypeLp); 343 WDMUtils.RSA rwa = computeValidPathNewRoute (cplNodePair , currentNetPlan , numSlots , maxOpticalReachKm , isSignalRegenerationPossible); 344 if (rwa != null) 345 { 346 WDMUtils.releaseResources(new WDMUtils.RSA (r , false) , wavelengthFiberOccupancy, null); 347 WDMUtils.allocateResources(rwa , wavelengthFiberOccupancy , null); 348 r.setSeqLinks(rwa.seqLinks); 349 WDMUtils.setLightpathRSAAttributes(r , rwa , false); 350 351 this.stat_numSuccessfullyRecoveredConnections ++; 352 this.stat_trafficSuccessfullyRecoveredConnections += r.getCarriedTrafficInNoFailureState(); 353 } 354 } 355 } 356 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 357 358 } else if (event.getEventObject () instanceof SimEvent.DemandModify) 359 { 360 SimEvent.DemandModify ev = (SimEvent.DemandModify) event.getEventObject (); 361 Demand d = ev.demand; 362 if (ev.modificationIsRelativeToCurrentOfferedTraffic) 363 d.setOfferedTraffic(d.getOfferedTraffic() + ev.offeredTraffic); 364 else 365 d.setOfferedTraffic(ev.offeredTraffic); 366 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 367 } else if (event.getEventObject () instanceof SimEvent.DemandRemove) 368 { 369 SimEvent.DemandRemove ev = (SimEvent.DemandRemove) event.getEventObject (); 370 Demand d = ev.demand; 371 for (Route lpToRemove : new ArrayList<> (d.getRoutes())) 372 { 373 WDMUtils.releaseResources(new WDMUtils.RSA(lpToRemove , false), wavelengthFiberOccupancy, null); 374 lpToRemove.remove(); 375 transponderTypeOfNewLps.remove(lpToRemove); 376 } 377 d.remove(); 378 if (DEBUG) { checkWaveOccupEqualsNp(currentNetPlan); checkClashing (currentNetPlan); } 379 } 380 else if(event.getEventObject() instanceof WDMUtils.LightpathModify) 381 { 382 WDMUtils.LightpathModify modifyLpEvent = (WDMUtils.LightpathModify) event.getEventObject(); 383 final Route lpRoute = modifyLpEvent.lp; 384 if (lpRoute != null) 385 { 386 WDMUtils.RSA oldRSA = new WDMUtils.RSA(lpRoute , false); 387 final Integer tpType = transponderTypeOfNewLps.get (lpRoute); 388 if (modifyLpEvent.rsa == null) throw new Net2PlanException ("Modifying the lightpath line rate requires setting the RSA also"); 389 if (tpType == null) throw new Net2PlanException ("Cannot find the transponder type of the lightpath!"); 390 if ((modifyLpEvent.carriedTraffic != 0) && (modifyLpEvent.carriedTraffic != tpInfo.getLineRateGbps(tpType))) throw new Net2PlanException ("Cannot change the line rate of an existing lightpath"); 391 if ((modifyLpEvent.rsa.getNumSlots() != 0) && (modifyLpEvent.rsa.getNumSlots() != tpInfo.getNumSlots(tpType))) throw new Net2PlanException ("Cannot change the number of slots of an existing lightpath"); 392 if ((modifyLpEvent.rsa.getLengthInKm() > tpInfo.getOpticalReachKm(tpType)) && (!tpInfo.isOpticalRegenerationPossible(tpType))) throw new Net2PlanException ("Cannot modify the lightpath RSA in sucha way that the lightpath length exceeds the transponder maximum reach"); 393 394 lpRoute.setCarriedTraffic(modifyLpEvent.carriedTraffic, modifyLpEvent.rsa.getNumSlots()); 395 WDMUtils.releaseResources( oldRSA, wavelengthFiberOccupancy , null); 396 WDMUtils.allocateResources(modifyLpEvent.rsa , wavelengthFiberOccupancy , null); 397 lpRoute.setSeqLinks(modifyLpEvent.rsa.seqLinks); 398 WDMUtils.setLightpathRSAAttributes(lpRoute , modifyLpEvent.rsa , false); 399 } 400 } 401 else throw new Net2PlanException ("Unknown event type: " + event); 402 } catch (Exception e) { 403 e.printStackTrace(); 404 throw e; 405 } 406 } 407 @Override 408 public String finish(StringBuilder output, double simTime) 409 { 410 final double trafficBlockingOnConnectionSetup = stat_trafficOfferedConnections == 0? 0 : 1 - (stat_trafficCarriedConnections / stat_trafficOfferedConnections ); 411 final double connectionBlockingOnConnectionSetup = stat_numOfferedConnections == 0? 0.0 : 1 - (((double) stat_numCarriedConnections) / ((double) stat_numOfferedConnections)); 412 final double successProbabilityRecovery = stat_numAttemptedToRecoverConnections == 0? 0.0 : (((double) stat_numSuccessfullyRecoveredConnections) / ((double) stat_numAttemptedToRecoverConnections)); 413 final double successProbabilityTrafficRecovery = stat_trafficAttemptedToRecoverConnections == 0? 0.0 : (((double) stat_trafficSuccessfullyRecoveredConnections) / ((double) stat_trafficAttemptedToRecoverConnections)); 414 final double dataTime = simTime - stat_transitoryInitTime; 415 if (dataTime <= 0) { output.append ("<p>No time for data acquisition</p>"); return ""; } 416 417 output.append (String.format("<p>Total traffic of offered connections: number connections %d, total time average traffic: %f</p>", stat_numOfferedConnections, stat_trafficOfferedConnections / dataTime)); 418 output.append (String.format("<p>Total traffic of carried connections: number connections %d, total time average traffic: %f</p>", stat_numCarriedConnections, stat_trafficCarriedConnections / dataTime)); 419 output.append (String.format("<p>Blocking at connection setup: Probability of blocking a connection: %f, Fraction of blocked traffic: %f</p>", connectionBlockingOnConnectionSetup , trafficBlockingOnConnectionSetup)); 420 output.append (String.format("<p>Number connections attempted to recover: %d (summing time average traffic: %f). </p>", stat_numAttemptedToRecoverConnections, stat_trafficAttemptedToRecoverConnections / dataTime)); 421 output.append (String.format("<p>Number connections successfully recovered: %d (summing time average traffic: %f). </p>", stat_numSuccessfullyRecoveredConnections, stat_trafficSuccessfullyRecoveredConnections / dataTime)); 422 output.append (String.format("<p>Probability of successfully recover a connection: %f. Proability weighted by the connection traffic: %f). </p>", successProbabilityRecovery, successProbabilityTrafficRecovery)); 423// output.append (String.format("<p>Total traffic carried at current state: %f. </p>", -1); 424 return ""; 425 } 426 427 @Override 428 public void finishTransitory(double simTime) 429 { 430 this.stat_trafficOfferedConnections = 0; 431 this.stat_trafficCarriedConnections = 0; 432 this.stat_trafficAttemptedToRecoverConnections = 0; 433 this.stat_trafficSuccessfullyRecoveredConnections = 0; 434 this.stat_numOfferedConnections = 0; 435 this.stat_numCarriedConnections = 0; 436 this.stat_numAttemptedToRecoverConnections = 0; 437 this.stat_numSuccessfullyRecoveredConnections = 0; 438 this.stat_transitoryInitTime = simTime; 439 } 440 441 442 /* down links or segments cannot be used */ 443 private WDMUtils.RSA computeValidPathNewRoute (Pair<Node,Node> cplNodePair , NetPlan currentNetPlan , int numContiguousSlots , double opticalReachKm , boolean isSignalRegenerationPossible) 444 { 445 /* If load sharing */ 446 final double maxLightpathLengthKm = isSignalRegenerationPossible? Double.MAX_VALUE : opticalReachKm; 447 if (isLoadSharing) 448 { 449 final List<List<Link>> paths = getAndUpdateCplWdm(cplNodePair, currentNetPlan); 450 final int randomChosenIndex = rng.nextInt(paths.size ()); 451 final List<Link> seqLinksThisNetPlan = paths.get(randomChosenIndex); 452 final Triple<Boolean,Integer,Double> rwaEval = computeValidWAFirstFit_path (seqLinksThisNetPlan , numContiguousSlots , maxLightpathLengthKm); 453 if (rwaEval.getFirst()) return new WDMUtils.RSA (seqLinksThisNetPlan, rwaEval.getSecond() , numContiguousSlots , WDMUtils.computeRegeneratorPositions(seqLinksThisNetPlan , maxLightpathLengthKm)); else return null; 454 } 455 else if (isAlternateRouting || isLeastCongestedRouting) 456 { 457 /* If alternate or LCR */ 458 WDMUtils.RSA lcrSoFar = null; double lcrIdleCapacitySoFar = -Double.MAX_VALUE; 459 for (List<Link> seqLinks : getAndUpdateCplWdm(cplNodePair, currentNetPlan)) 460 { 461 final Triple<Boolean,Integer,Double> rwaEval = computeValidWAFirstFit_path (seqLinks , numContiguousSlots , maxLightpathLengthKm); 462 if (!rwaEval.getFirst()) continue; 463 if (isAlternateRouting) return new WDMUtils.RSA (seqLinks, rwaEval.getSecond(),numContiguousSlots , WDMUtils.computeRegeneratorPositions(seqLinks , maxLightpathLengthKm)); 464 if (rwaEval.getThird() > lcrIdleCapacitySoFar) 465 { 466 lcrIdleCapacitySoFar = rwaEval.getThird(); 467 lcrSoFar = new WDMUtils.RSA (seqLinks , rwaEval.getSecond()); 468 } 469 } 470 return (isAlternateRouting || (lcrSoFar == null))? (WDMUtils.RSA) null : lcrSoFar; 471 } 472 else if (isSrgDisjointAwareLpRouting) 473 { 474 final Node thisNpIngressNode = cplNodePair.getFirst(); 475 final Node thisNpEgressNode = cplNodePair.getSecond(); 476 WDMUtils.RSA chosenRWA = null; 477 final Set<Route> existingPrimaryRoutesBetweenPairOfNodes = currentNetPlan.getNodePairRoutes(thisNpIngressNode, thisNpEgressNode , false , wdmLayer); 478 int cplChosenRoute_numSRGOverlappingRoutes = Integer.MAX_VALUE; 479 for(List<Link> seqLinks : getAndUpdateCplWdm(cplNodePair, currentNetPlan)) 480 { 481 /* Check that the route has an available wavlength */ 482 final Triple<Boolean,Integer,Double> rwaEval = computeValidWAFirstFit_path (seqLinks , numContiguousSlots , maxLightpathLengthKm); 483 if (!rwaEval.getFirst()) continue; 484 /* compute the number of SRG-route pairs this route overlaps with, respect to the already existing lightpaths */ 485 Set<SharedRiskGroup> affectingSRGs = SRGUtils.getAffectingSRGs(seqLinks); 486 int numOverlappingSRGs = 0; 487 for (Route currentRoute : existingPrimaryRoutesBetweenPairOfNodes) 488 for (SharedRiskGroup srg : currentRoute.getSRGs()) if (affectingSRGs.contains(srg)) numOverlappingSRGs ++; 489 if (numOverlappingSRGs < cplChosenRoute_numSRGOverlappingRoutes) 490 { 491 cplChosenRoute_numSRGOverlappingRoutes = numOverlappingSRGs; 492 chosenRWA = new WDMUtils.RSA (seqLinks , rwaEval.getSecond(),numContiguousSlots , WDMUtils.computeRegeneratorPositions(seqLinks, maxLightpathLengthKm)); 493 if (numOverlappingSRGs == 0) break; // no need to search more 494 } 495 } 496 return chosenRWA; 497 } 498 throw new RuntimeException ("Bad"); 499 } 500 501 private Pair<WDMUtils.RSA,WDMUtils.RSA> computeValid11PathPairNewRoute (Pair<Node,Node> cplNodePair , NetPlan currentNetPlan , int numContigousSlotsOccupies , double opticalReachKm , boolean isSignalRegenerationPossible) 502 { 503 final double maximumLengthOfLighptathKm = isSignalRegenerationPossible? Double.MAX_VALUE : opticalReachKm; 504 505 /* If load sharing */ 506 if (isLoadSharing) 507 { 508 final List<Pair<List<Link>,List<Link>>> routePairs = getAndUpdateCplWdm11(cplNodePair, currentNetPlan); 509 final int randomChosenIndex = rng.nextInt(routePairs.size()); 510 final List<Link> seqLinksPrimaryThisNetPlan = routePairs.get(randomChosenIndex).getFirst(); 511 final List<Link> seqLinksBackupThisNetPlan = routePairs.get(randomChosenIndex).getSecond(); 512 final Quadruple<Boolean,Integer,Integer,Double> rwaEval = computeValidWAFirstFit_pathPair (seqLinksPrimaryThisNetPlan , seqLinksBackupThisNetPlan , numContigousSlotsOccupies , maximumLengthOfLighptathKm); 513 if (rwaEval.getFirst()) 514 return Pair.of(new WDMUtils.RSA (seqLinksPrimaryThisNetPlan, rwaEval.getSecond() , numContigousSlotsOccupies , WDMUtils.computeRegeneratorPositions(seqLinksPrimaryThisNetPlan, maximumLengthOfLighptathKm)) , new WDMUtils.RSA (seqLinksBackupThisNetPlan, rwaEval.getThird() , numContigousSlotsOccupies , WDMUtils.computeRegeneratorPositions(seqLinksBackupThisNetPlan , maximumLengthOfLighptathKm))); 515 else 516 return null; 517 } 518 else if (isAlternateRouting || isLeastCongestedRouting) 519 { 520 Pair<WDMUtils.RSA,WDMUtils.RSA> lcrSoFar = null; double lcrIdleCapacitySoFar= -Double.MAX_VALUE; 521 for (Pair<List<Link>,List<Link>> pathPair : getAndUpdateCplWdm11(cplNodePair, currentNetPlan)) 522 { 523 final List<Link> seqLinksPrimaryThisNetPlan = pathPair.getFirst(); 524 final List<Link> seqLinksBackupThisNetPlan = pathPair.getSecond(); 525 final Quadruple<Boolean,Integer,Integer,Double> rwaEval = computeValidWAFirstFit_pathPair (seqLinksPrimaryThisNetPlan , seqLinksBackupThisNetPlan , numContigousSlotsOccupies , maximumLengthOfLighptathKm); 526 if (!rwaEval.getFirst()) continue; 527 if (isAlternateRouting) return Pair.of(new WDMUtils.RSA (seqLinksPrimaryThisNetPlan, rwaEval.getSecond() , numContigousSlotsOccupies , WDMUtils.computeRegeneratorPositions(seqLinksPrimaryThisNetPlan , maximumLengthOfLighptathKm)) , new WDMUtils.RSA (seqLinksBackupThisNetPlan, rwaEval.getThird() , numContigousSlotsOccupies , WDMUtils.computeRegeneratorPositions(seqLinksBackupThisNetPlan , maximumLengthOfLighptathKm))); 528 if (rwaEval.getFourth() > lcrIdleCapacitySoFar) 529 { 530 lcrIdleCapacitySoFar = rwaEval.getFourth(); 531 lcrSoFar = Pair.of(new WDMUtils.RSA (seqLinksPrimaryThisNetPlan , rwaEval.getSecond()) , new WDMUtils.RSA (seqLinksBackupThisNetPlan , rwaEval.getThird())); 532 } 533 } 534 return lcrSoFar; //if alternate, this is null also 535 } else if (isSrgDisjointAwareLpRouting) 536 { 537 final Node thisNpIngressNode = cplNodePair.getFirst(); 538 final Node thisNpEgressNode = cplNodePair.getSecond(); 539 Pair<WDMUtils.RSA,WDMUtils.RSA> chosenRWA = null; 540 Set<Route> existingRoutesBetweenPairOfNodes = currentNetPlan.getNodePairRoutes(thisNpIngressNode, thisNpEgressNode , false , wdmLayer).stream().filter(e -> !e.isBackupRoute()).collect(Collectors.toSet()); 541 int cplChosenRoute_numSRGOverlappingRoutes = Integer.MAX_VALUE; 542 for(Pair<List<Link>,List<Link>> pathPair : getAndUpdateCplWdm11(cplNodePair, currentNetPlan)) 543 { 544 final List<Link> seqLinksPrimaryThisNetPlan = pathPair.getFirst(); 545 final List<Link> seqLinksBackupThisNetPlan = pathPair.getSecond(); 546 final Quadruple<Boolean,Integer,Integer,Double> rwaEval = computeValidWAFirstFit_pathPair (seqLinksPrimaryThisNetPlan , seqLinksBackupThisNetPlan , numContigousSlotsOccupies , maximumLengthOfLighptathKm); 547 if (!rwaEval.getFirst()) continue; 548 /* compute the number of SRG-route pairs this route overlaps with, respect to the already existing lightpaths */ 549 final Set<SharedRiskGroup> affectingSRGs_primaryOrBackup = SRGUtils.getAffectingSRGs(seqLinksPrimaryThisNetPlan); 550 affectingSRGs_primaryOrBackup.addAll(SRGUtils.getAffectingSRGs(seqLinksBackupThisNetPlan)); 551 int numOverlappingSRGs = 0; 552 for (Route currentRoute : existingRoutesBetweenPairOfNodes) 553 { 554 for (SharedRiskGroup srg : currentRoute.getSRGs()) if (affectingSRGs_primaryOrBackup.contains (srg)) numOverlappingSRGs ++; 555 Set<SharedRiskGroup> affectingSRGs = currentRoute.hasBackupRoutes()? currentRoute.getBackupRoutes().get(0).getSRGs() : new HashSet<> (); 556 for (SharedRiskGroup srg : affectingSRGs) if (affectingSRGs_primaryOrBackup.contains(srg)) numOverlappingSRGs ++; 557 } 558 if (numOverlappingSRGs < cplChosenRoute_numSRGOverlappingRoutes) 559 { 560 cplChosenRoute_numSRGOverlappingRoutes = numOverlappingSRGs; 561 chosenRWA = Pair.of (new WDMUtils.RSA (seqLinksPrimaryThisNetPlan , rwaEval.getSecond() , 562 numContigousSlotsOccupies , 563 WDMUtils.computeRegeneratorPositions(seqLinksPrimaryThisNetPlan , maximumLengthOfLighptathKm)) , 564 new WDMUtils.RSA (seqLinksBackupThisNetPlan , rwaEval.getThird() , numContigousSlotsOccupies , 565 WDMUtils.computeRegeneratorPositions(seqLinksBackupThisNetPlan , maximumLengthOfLighptathKm))); 566 if (numOverlappingSRGs == 0) break; // no need to search more 567 } 568 } 569 return chosenRWA; 570 } 571 throw new RuntimeException ("Bad"); 572 } 573 574 private Triple<Boolean,Integer,Double> computeValidWAFirstFit_path (List<Link> seqLinks , int numContiguousSlots , double maxOpticalReachKm) 575 { 576 if (seqLinks.isEmpty()) throw new RuntimeException ("Bad"); 577 if (seqLinks.get(0).getOriginNode().isDown()) return Triple.of(false,-1,-1.0); 578 if (getLengthInKm(seqLinks) > maxOpticalReachKm) return Triple.of(false,-1,-1.0); 579 double worseCaseSpareCapacity = Double.MAX_VALUE; 580 for (Link e : seqLinks) 581 { 582 worseCaseSpareCapacity = Math.min(worseCaseSpareCapacity, e.getCapacity() - e.getOccupiedCapacity()); 583 if (e.getDestinationNode().isDown() || e.isDown()) return Triple.of(false,-1,-1.0); 584 } 585 int wavelength = WDMUtils.spectrumAssignment_firstFit(seqLinks, wavelengthFiberOccupancy , numContiguousSlots); 586 if (wavelength != -1) 587 return Triple.of(true , wavelength , worseCaseSpareCapacity); 588 else return Triple.of(false,-1,-1.0); 589 } 590 591 private Quadruple<Boolean,Integer,Integer,Double> computeValidWAFirstFit_pathPair (List<Link> seqLinks_1 , List<Link> seqLinks_2 , int numSlots , double maxOpticalReachKm) 592 { 593 if (seqLinks_1.isEmpty() || seqLinks_2.isEmpty()) throw new RuntimeException ("Bad"); 594 if (seqLinks_1.get(0).getOriginNode().isDown()) return Quadruple.of(false,-1,-1,-1.0); 595 if (seqLinks_2.get(0).getOriginNode().isDown()) return Quadruple.of(false,-1,-1,-1.0); 596 if (getLengthInKm(seqLinks_1) > maxOpticalReachKm) return Quadruple.of(false,-1,-1,-1.0); 597 if (getLengthInKm(seqLinks_2) > maxOpticalReachKm) return Quadruple.of(false,-1,-1,-1.0); 598 double worseCaseSpareCapacity = Double.MAX_VALUE; 599 for (Link e : seqLinks_1) 600 { 601 worseCaseSpareCapacity = Math.min(worseCaseSpareCapacity, e.getCapacity() - e.getOccupiedCapacity()); 602 if (e.getDestinationNode().isDown() || e.isDown()) return Quadruple.of(false,-1,-1,-1.0); 603 } 604 for (Link e : seqLinks_2) 605 { 606 worseCaseSpareCapacity = Math.min(worseCaseSpareCapacity, e.getCapacity() - e.getOccupiedCapacity()); 607 if (e.getDestinationNode().isDown() || e.isDown()) return Quadruple.of(false,-1,-1,-1.0); 608 } 609 Pair<Integer,Integer> seqWavelengths = WDMUtils.spectrumAssignment_firstFitTwoRoutes(seqLinks_1, seqLinks_2, wavelengthFiberOccupancy,numSlots); 610 if (seqWavelengths != null) 611 { 612 if (!WDMUtils.isAllocatableRSASet(wavelengthFiberOccupancy , new WDMUtils.RSA(seqLinks_1 , seqWavelengths.getFirst() , numSlots))) 613 throw new RuntimeException(); 614 if (!WDMUtils.isAllocatableRSASet(wavelengthFiberOccupancy , new WDMUtils.RSA(seqLinks_2 , seqWavelengths.getSecond() , numSlots))) 615 throw new RuntimeException(); 616 return Quadruple.of(true , seqWavelengths.getFirst () , seqWavelengths.getSecond() , worseCaseSpareCapacity); 617 } 618 else return Quadruple.of(false,-1,-1,-1.0); 619 } 620 621 private void checkClashing (NetPlan np) 622 { 623 WDMUtils.checkResourceAllocationClashing(np, false, false, wdmLayer); 624 } 625 626 private static void checkDisjointness (List<Link> p1 , List<Link> p2 , int disjointnessType) 627 { 628 if ((p1 == null) || (p2 == null)) throw new RuntimeException ("Bad"); 629 if (disjointnessType == 0) // SRG disjoint 630 { 631 Set<SharedRiskGroup> srg1 = new HashSet<SharedRiskGroup> (); for (Link e : p1) srg1.addAll (e.getSRGs()); 632 for (Link e : p2) for (SharedRiskGroup srg : e.getSRGs()) if (srg1.contains(srg)) throw new RuntimeException ("Bad"); 633 } 634 else if (disjointnessType == 1) // link and node 635 { 636 Set<NetworkElement> resourcesP1 = new HashSet<NetworkElement> (); boolean firstLink = true; 637 for (Link e : p1) { resourcesP1.add (e); if (firstLink) firstLink = false; else resourcesP1.add (e.getOriginNode()); } 638 for (Link e : p2) if (resourcesP1.contains(e)) throw new RuntimeException ("Bad"); 639 } 640 else if (disjointnessType == 2) // link 641 { 642 Set<Link> linksP1 = new HashSet<Link> (p1); 643 for (Link e : p2) if (linksP1.contains (e)) throw new RuntimeException ("Bad: p1: " + p1 + ", p2: " + p2); 644 } 645 else throw new RuntimeException ("Bad"); 646 647 } 648 649 private static double getLengthInKm (List<Link> p) { double res = 0; for (Link e : p) res += e.getLengthInKm(); return res; } 650 private void checkWaveOccupEqualsNp (NetPlan currentNetPlan) 651 { 652 DoubleMatrix2D freqNow_se = WDMUtils.getNetworkSlotAndRegeneratorOcupancy(currentNetPlan, true , wdmLayer).getFirst(); 653 if (!freqNow_se.equals(wavelengthFiberOccupancy)) 654 { 655 System.out.println(freqNow_se.assign(wavelengthFiberOccupancy , DoubleFunctions.minusMult(1.0))); 656 throw new RuntimeException (); 657 } 658 659 } 660 661 private List<List<Link>> getAndUpdateCplWdm (Pair<Node,Node> pair , NetPlan np) 662 { 663 List<List<Link>> res = cplWdm.get(pair); 664 if (res != null) return res; 665 final Map<Link,Double> linkCostMap = new HashMap<> (); for (Link e : np.getLinks(wdmLayer)) linkCostMap.put(e, e.getLengthInKm()); 666 res = GraphUtils.getKLooplessShortestPaths(np.getNodes(), np.getLinks(wdmLayer), pair.getFirst(), 667 pair.getSecond(), linkCostMap, wdmK.getInt(), tpInfo.getMaxOpticalReachKm(), wdmMaxLightpathNumHops.getInt(), -1, -1, -1, -1); 668 if (res.isEmpty()) throw new Net2PlanException ("There is no path between nodes: " + pair.getFirst() + " -> " + pair.getSecond()); 669 cplWdm.put(pair , res); 670 return res; 671 } 672 private List<Pair<List<Link>,List<Link>>> getAndUpdateCplWdm11 (Pair<Node,Node> pair , NetPlan np) 673 { 674 List<Pair<List<Link>,List<Link>>> res = cplWdm11.get(pair); 675 if (res != null) return res; 676 final List<List<Link>> basePathList = getAndUpdateCplWdm (pair , np); 677 final Map<Pair<Node,Node> , List<List<Link>>> singleNodePairCpl = new HashMap<>(); 678 singleNodePairCpl.put(pair , basePathList); 679 final Map<Pair<Node, Node>, List<Pair<List<Link>, List<Link>>>> cpl11ThisPair = 680 NetPlan.computeUnicastCandidate11PathList(singleNodePairCpl , protectionTypeCode); 681 if (cpl11ThisPair.isEmpty()) throw new Net2PlanException ("There is no 1+1 paths between nodes: " + pair.getFirst() + " -> " + pair.getSecond()); 682 cplWdm11.put(pair , cpl11ThisPair.get(pair)); 683 return cpl11ThisPair.get(pair); 684 } 685}