001/******************************************************************************* 002 * Copyright (c) 2017 Pablo Pavon Marino and others. 003 * All rights reserved. This program and the accompanying materials 004 * are made available under the terms of the 2-clause BSD License 005 * which accompanies this distribution, and is available at 006 * https://opensource.org/licenses/BSD-2-Clause 007 * 008 * Contributors: 009 * Pablo Pavon Marino and others - initial API and implementation 010 *******************************************************************************/ 011 012 013 014 015 016 017 018 019 020 021package com.net2plan.examples.general.reports; 022 023import com.net2plan.interfaces.networkDesign.*; 024import com.net2plan.libraries.GraphUtils; 025import com.net2plan.libraries.TrafficComputationEngine; 026import com.net2plan.libraries.WDMUtils; 027import com.net2plan.utils.InputParameter; 028import com.net2plan.utils.Pair; 029import com.net2plan.utils.Triple; 030 031import java.text.DecimalFormat; 032import java.util.HashMap; 033import java.util.LinkedList; 034import java.util.List; 035import java.util.Map; 036import java.util.stream.Collectors; 037 038/** 039 * 040 * <p>This report collects information about the Routing and Spectrum assignment in the network, as well as other general information about the WDM layer.</p> 041 * <p>This report is valid for the WDM layers compatible with the {@link com.net2plan.libraries.WDMUtils WDMUtils} library .This includes both fixed and flexi-grid networks, 042 * with unique or mixed line rates in the lightpaths, with or without optical signal regenerators and wavelength (frequency slot) conversions.</p> 043 * <p>The report first checks that the WDM network follows the conventions described in {@link com.net2plan.libraries.WDMUtils WDMUtils} library (see its Javadoc for further information on this).</p> 044 * <p>Then, the report provides a number of statistics regarding frequency slot occupation, optical signal 045 * regenerators, wavelength (frequency slot) converters needed, etc. It also warns about possible frequency slot clashing 046 * two lightpaths using the same slot in the same fibers)</p> 047 * <p>Lightpaths are separated into:</p> 048 * <ul> 049 * <li>Regular lightpaths: Those stored as {@code Route} objects in the design.</li> 050 * <li>Protection lightpaths: Those stored as {@code ProtectionSegment} objects in the design.</li> 051 * </ul> 052 * @net2plan.keywords WDM 053 * @author Pablo Pavon-Marino 054 */ 055public class Report_wdm_routingSpectrumAndModulationAssignments implements IReport 056{ 057 /* Input parameters */ 058 private NetPlan netPlan; 059 private NetworkLayer wdmLayer; 060 private Map<String, String> reportParameters; 061 private Statistics stat; 062 private InputParameter wdmLayerIndex = new InputParameter ("wdmLayerIndex", (int) 0 , "Index of the WDM layer (-1 means default layer)"); 063 064 @Override 065 public String executeReport(NetPlan netPlan, Map<String, String> reportParameters, Map<String, String> net2planParameters) 066 { 067 /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */ 068 InputParameter.initializeAllInputParameterFieldsOfObject(this, reportParameters); 069 070 /* Input parameters */ 071 this.netPlan = netPlan; 072 this.reportParameters = reportParameters; 073 final NetworkLayer originalDefaultLayer = netPlan.getNetworkLayerDefault(); 074 this.wdmLayer = wdmLayerIndex.getInt () == -1? netPlan.getNetworkLayerDefault() : netPlan.getNetworkLayer(wdmLayerIndex.getInt ()); 075 this.netPlan.setNetworkLayerDefault(wdmLayer); 076 077 //Map<Link, LinkedList<String>> warnings_e = new LinkedHashMap<Link, LinkedList<String>>(); 078 079 String res = printReport(); 080 netPlan.setNetworkLayerDefault(originalDefaultLayer); 081 return res; 082 } 083 084 @Override 085 public String getDescription() 086 { 087 return "This report shows line engineering information for WDM links in the network. Further description in the HTML generated."; 088 } 089 090 @Override 091 public List<Triple<String, String, String>> getParameters() 092 { 093 /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */ 094 return InputParameter.getInformationAllInputParameterFieldsOfObject(this); 095 } 096 097 @Override 098 public String getTitle() 099 { 100 return "WDM line engineering"; 101 } 102 103 private String printReport() 104 { 105 StringBuilder out = new StringBuilder(); 106 DecimalFormat df_2 = new DecimalFormat("###.##"); 107 108 out.append("<html><body>"); 109 out.append("<head><title>WDM Lightpath Routing and Spectrum Assignment (fixed or flexi-grid networks) report</title></head>"); 110 out.append("<h1>WDM Lightpath Routing and Spectrum Assignment report (fixed or flexi-grid networks)</h1>"); 111 out.append("<p>This report collects information about the Routing and Spectrum assignment in the network, as well as other general information about the WDM layer.</p>"); 112 out.append("<p>This report is valid for the WDM layers compatible with the WDMUtils library .This includes both fixed and flexi-grid networks, " 113 + "with unique or mixed line rates in the lightpaths, with or without optical signal regenerators and wavelength (frequency slot) conversions.</p>"); 114 out.append("<p>The report first checks that the WDM network follows the conventions described in WDMUtils library (see its Javadoc for further information on this).</p>"); 115 out.append("<p>Then, the report provides a number of statistics regarding frequency slot occupation, optical signal " 116 + "regenerators, wavelength (frequency slot) converters needed, etc. It also warns about possible frequency slot clashing " 117 + "(two lightpaths using the same slot in the same fibers)</p>"); 118 out.append("<p>Lightpaths are separated into:</p>"); 119 out.append("<ul>"); 120 out.append("<li>Regular lightpaths: Those stored as Route objects in the design.</li>"); 121 out.append("<li>Protection lightpaths: Those stored as ProtectionSegment objects in the design.</li>"); 122 out.append("</ul>"); 123 out.append("<h2>Click to go to...</h2>"); 124 out.append("<ul>"); 125 out.append("<li><a href=\"#inputParameters\">Input parameters</a></li>"); 126 out.append("<li><a href=\"#generalStats\">General statistics</a></li>"); 127 out.append("<li><a href=\"#linkStats\">Per fiber statistics (including slot occupation map)</a></li>"); 128 out.append("<li><a href=\"#routeStats\">Per regular lightpath statistics</a></li>"); 129 out.append("<li><a href=\"#protectionStats\">Per protection lightpath statistics</a></li>"); 130 out.append("<li><a href=\"#nodeStats\">Per OADM statistics</a></li>"); 131 out.append("</ul>"); 132 133 134 out.append("<h2><a name=\"inputParameters\"></a>Input Parameters</h2>"); 135 out.append("<table border='1'>"); 136 out.append("<tr><th><b>Name</b></th><th><b>Value</b></th><th><b>Description</b></th>"); 137 138 for (Triple<String, String, String> paramDef : getParameters()) 139 { 140 String name = paramDef.getFirst(); 141 String description = paramDef.getThird(); 142 String value = reportParameters.get(name); 143 out.append("<tr><td>").append(name).append("</td><td>").append(value).append("</td><td>").append(description).append("</td></tr>"); 144 } 145 out.append("</table>"); 146 147 /* Check that the topology is well formed */ 148 out.append("<h2><a name=\"malformedMessages\"></a>MALFORMED WDM LAYER WARNINGS</h2>"); 149 out.append("<p>This section gets possible format errors in the WDM layer attributes of links, routes, protection segments, according to the " 150 + "WDMUtils library conventions. Resource allocation clashings are not checked here. Any failure should be solved before this report can show any information</p>"); 151 boolean correctFormat = true; 152 out.append("<table border='1'>"); 153 out.append("<tr><th align=\"left\" colspan=\"2\"><b>Format errors</b></th></tr>"); 154 for (Link e : netPlan.getLinks()) if (!WDMUtils.isWDMFormatCorrect(e)) { correctFormat = false ; out.append("<tr><td>Fiber " + e.getIndex() + ": incorrect format</td></tr>"); } 155 for (Route r : netPlan.getRoutes(wdmLayer)) if (!WDMUtils.isWDMFormatCorrect(r)) { correctFormat = false ; out.append("<tr><td>Route " + r.getIndex() + ": incorrect format. Is backup route: " + r.isBackupRoute() + "</td></tr>"); } 156 if (correctFormat) out.append("<tr><td bgcolor=\"PaleGreen\">No format errors!!!</td></tr>"); 157 out.append("</table>"); 158 if (!correctFormat) return out.toString(); 159 160 this.stat = new Statistics(netPlan,netPlan.getNetworkLayerDefault()); 161 out.append("<h2><a name=\"generalStats\"></a>GENERAL STATISTICS - Signal metrics at the input of end OADM</h2>"); 162 out.append("<table border='1'>"); 163 out.append("<tr><th align=\"left\" colspan=\"2\"><b>OADM stats</b></th></tr>"); 164 out.append("<tr><td align=\"left\">Number of OADMs</td><td>" + netPlan.getNumberOfNodes() + "</td></tr>"); 165 out.append("<tr><td align=\"left\">Node in degree (min/average/max)</td><td>" + stat.nodeInDegree.toString(df_2) + "</td></tr>"); 166 out.append("<tr><td align=\"left\">Node out degree (min/average/max)</td><td>" + stat.nodeOutDegree.toString(df_2) + "</td></tr>"); 167 168 out.append("<tr><th align=\"left\" colspan=\"2\"><b>Fiber link stats</b></td></tr>"); 169 out.append("<tr><td align=\"left\">Number of fibers</td><td>" + netPlan.getNumberOfLinks() + "</td></tr>"); 170 out.append("<tr><td align=\"left\">Number of frequency slots per fiber (min/average/max)</td><td>" + stat.numberFrequencySlotsPerLink + "</td></tr>"); 171 out.append("<tr><td align=\"left\">Number of slots occupied per fiber (min/average/max)</td><td>" + stat.linkUtilization.toString(df_2) + "</td></tr>"); 172 out.append("<tr><td align=\"left\">The topology of fibers is bidirectional (in fibers and number of slots)?</td><td>" + stat.bidirectionalLinks + "</td></tr>"); 173 174 out.append("<tr><th align=\"left\" colspan=\"2\"><b>Traffic stats</b></td></tr>"); 175 out.append("<tr><td align=\"left\">Number of demands</td><td>" + netPlan.getNumberOfDemands() + "</td></tr>"); 176 final double offeredTraffic = netPlan.getVectorDemandOfferedTraffic().zSum(); 177 final double blockedTraffic = netPlan.getVectorDemandBlockedTraffic().zSum(); 178 out.append("<tr><td align=\"left\">Total offered traffic</td><td>" + df_2.format(offeredTraffic) + "</td></tr>"); 179 out.append("<tr><td align=\"left\">Total blocked traffic</td><td>" + df_2.format(blockedTraffic) + "(block prob: " + df_2.format(offeredTraffic == 0? 0 : blockedTraffic / offeredTraffic) + ")" + "</td></tr>"); 180 out.append("<tr><td align=\"left\">The offered traffic is symmetric?</td><td>" + stat.bidirectionalDemands + "</td></tr>"); 181 182 out.append("<tr><th align=\"left\" colspan=\"2\"><b>Lightpath stats</b></td></tr>"); 183 out.append("<tr><td align=\"left\">Number of lightpaths (route objects)</td><td>" + netPlan.getNumberOfRoutes() + "</td></tr>"); 184 out.append("<tr><td align=\"left\">The lightpaths are bidirectional? (same number of the same line rate between each node pair)?</td><td>" + stat.bidirectionalRoutes + "</td></tr>"); 185 out.append("<tr><td align=\"left\">Some demands are carried by more than one lightpath?</td><td>" + stat.unicastRoutingBifurcated + "</td></tr>"); 186 out.append("<tr><td align=\"left\">Lightpath length in km (min/average/max)</td><td>" + stat.lpLengthKm.toString(df_2) + "</td></tr>"); 187 out.append("<tr><td align=\"left\">Lightpath length in num hops (min/average/max)</td><td>" + stat.lpLengthHops.toString(df_2) + "</td></tr>"); 188 out.append("<tr><td align=\"left\">Lightpath propagation delay in ms (min/average/max)</td><td>" + stat.lpLengthMs.toString(df_2) + "</td></tr>"); 189 out.append("<tr><td align=\"left\">Total number of signal regenerators placed</td><td>" + stat.numberOfSignalRegenerators + "</td></tr>"); 190 out.append("<tr><td align=\"left\">Total number of frequency slot converters needed</td><td>" + stat.numberOfWavelengthConversions + "</td></tr>"); 191 192 out.append("<tr><th align=\"left\" colspan=\"2\"><b>Resilience stats</b></th></tr>"); 193 out.append("<tr><td align=\"left\">The protection lightpaths are bidirectional? (same number of the same number of slots reserved between each node pair)?</td><td>" + stat.bidirectionalProtectionSegments + "</td></tr>"); 194 out.append("<tr><td align=\"left\">Fiber capacity (number of slots) reserved for protection (min/average/max)</td><td>" + stat.fiberCapacityOccupiedByBackupRoutes.toString(df_2) + "</td></tr>"); 195 final double resilienceInfo = TrafficComputationEngine.getTrafficProtectionDegree(netPlan); 196 out.append("<tr><td align=\"left\">% of carried traffic with at least one backup path</td><td>" + df_2.format(resilienceInfo) + " %" + "</td></tr>"); 197 out.append("</table>"); 198 199 /* Per link information */ 200 out.append("<h2><a name=\"linkStats\"></a>PER FIBER INFORMATION SUMMARY</h2>"); 201 out.append("<p>This table shows information for each fiber. In particular, the slots occupied, with a link to the lightpaths occupying it, either for regular lightpaths (L), or lightpaths defined as protection segments (P) that reserve slots:</p>"); 202 out.append("<ul>"); 203 out.append("<li>Black: The slot number is higher than the capacity declared for the link, and is not assigned to any lightpath.</li>"); 204 out.append("<li>White: The slot is within the fiber capacity, and is not assigned to any lightpath.</li>"); 205 out.append("<li>Green: The slot is within the fiber capacity, and is occupied by one regular lightpath and assigned to no backup lightpath.</li>"); 206 out.append("<li>Yellow: The slot is within the fiber capacity, and is occupied by zero regular lightpaths and assigned to one backup lightpath.</li>"); 207 out.append("<li>Red: The slot is within the fiber capacity, and is occupied by more than one lightpath (summing regular and backup), or is outside the link capacity and is assigned to at leastone lightpath.</li>"); 208 out.append("</ul>"); 209 out.append("<table border='1'>"); 210 out.append("<tr><th><b>Fiber #</b></th><th><b>Origin node</b></th><th><b>Dest. node</b></th><th><b>% slots used</b></th><th><b>Ok?</b></th>"); 211 for (int s = 0; s < stat.maxNumberSlots ; s ++) out.append("<th>" + s + "</th>"); 212 out.append("</tr>"); 213 214 for (Link e : netPlan.getLinks()) 215 { 216 final int numSlotsThisFiber = WDMUtils.getFiberNumFrequencySlots(e); 217 out.append("<tr>"); 218 out.append("<td><a name=\"fiber" + e.getIndex() + "\">" + e.getIndex() + " (id: " + e.getId() + ")"+ "</a></td>"); 219 out.append("<td>" + printNode (e.getOriginNode()) + "</td>"); 220 out.append("<td>" + printNode (e.getDestinationNode()) + "</td>"); 221 int numSlotsUsedThisFiber = 0; 222 boolean everythingOk = true; 223 StringBuffer thisLine = new StringBuffer (); 224 for (int s = 0; s < stat.maxNumberSlots ; s ++) 225 { 226 List<Route> lps = stat.slotOccupInfo.get(Pair.of(e,s)); 227 if (lps == null) lps = new LinkedList<> (); 228// List<Route> lps = lists == null? null : lists.getFirst(); 229// List<ProtectionSegment> lpProts = lists == null? null : lists.getSecond(); 230 String color = ""; 231 final boolean inFiberCapacity = (s < numSlotsThisFiber); 232 final int numLpsBackup = (int) lps.stream().filter(ee -> ee.isBackupRoute()).count(); 233 final int numLpsPrimary = lps.size() - numLpsBackup; 234 numSlotsUsedThisFiber += numLpsPrimary + numLpsBackup > 0? 1 : 0; 235 if (!inFiberCapacity && (numLpsPrimary + numLpsBackup == 0)) color = "black"; 236 else if (!inFiberCapacity && (numLpsPrimary + numLpsBackup > 0)) { color = "red"; everythingOk = false; } 237 else if (inFiberCapacity && (numLpsPrimary + numLpsBackup == 0)) color = "white"; 238 else if (inFiberCapacity && (numLpsPrimary == 1) && (numLpsBackup == 0)) color = "PaleGreen"; 239 else if (inFiberCapacity && (numLpsPrimary == 0) && (numLpsBackup == 1)) color = "yellow"; 240 else { color = "red"; everythingOk = false; } 241 thisLine.append("<td bgcolor=\"" + color + "\">"); 242 if (lps != null) for (Route r : lps) thisLine.append("<a href=\"#lp" + r.getIndex() + "\">L" + r.getIndex() + " </a>"); 243 thisLine.append("</td>"); 244 } 245 out.append("<td>" + ((double) numSlotsUsedThisFiber) / ((double) numSlotsThisFiber) + "</td>"); 246 out.append("<td bfcolor=\"" + (everythingOk? "PaleGreen" : "red") +"\">" + (everythingOk? "Yes" : "No") + "</td>"); 247 out.append(thisLine.toString()); 248 out.append("</tr>"); 249 } 250 out.append("</table>"); 251 252 /* Per Route lightpath information */ 253 out.append("<h2><a name=\"routeStats\"></a>PER LIGHTPATH (NON BACKUP) INFORMATION SUMMARY</h2>"); 254 out.append("<p>This table shows information for each regular lightpath (not backup lightpaths).</p>"); 255 out.append("<table border='1'>"); 256 out.append("<tr><th><b>Lighpath Route #</b></th><th><b>Demand #</b></th><th><b>Origin node</b></th>" 257 + "<th><b>Dest. node</b></th><th><b>Trav. nodes</b></th><th><b>Length (km)</b></th><th><b>Propagation delay (ms)</b></th>" 258 + "<th><b>Line rate (Gbps)</b></th><th><b>Num. slots</b></th><th><b>Occupied slots</b></th>" 259 + "<th><b>Wavelength conversion?</b></th><th><b>Wavelength contiguity?</b></th></th>" 260 + "<th><b>Num. regenerators (reg. nodes)</b></th><th><b>Backup routes assigned</b></th><th><b>Ok?</b></th></tr>"); 261 for (Route r : netPlan.getRoutesAreNotBackup(wdmLayer)) 262 { 263 WDMUtils.RSA rsa = new WDMUtils.RSA(r , false); 264 out.append("<tr>"); 265 out.append("<td><a name=\"lp" + r.getIndex() + "\">" + r.getIndex() + " (id: " + r.getId() + ")"+ "</a></td>"); 266 out.append("<td>" + r.getDemand().getIndex() + "</td>"); 267 out.append("<td>" + printNode(r.getIngressNode())+ "</td>"); 268 out.append("<td>" + printNode(r.getEgressNode())+ "</td>"); 269 out.append("<td>" + seqNodesString(r.getSeqLinks()) + "</td>"); 270 out.append("<td>" + df_2.format(r.getLengthInKm()) + "</td>"); 271 out.append("<td>" + df_2.format(r.getPropagationDelayInMiliseconds()) + "</td>"); 272 out.append("<td>" + df_2.format(r.getCarriedTraffic()) + "</td>"); 273 out.append("<td>" + rsa.getNumSlots() + "</td>"); 274 out.append("<td>" + occupiedSlotsString(rsa) + "</td>"); 275 out.append("<td>" + rsa.hasFrequencySlotConversions() + "</td>"); 276 out.append("<td>" + rsa.isFrequencySlotContiguous () + "</td>"); 277 List<Node> regPoints = rsa.getSignalRegenerationNodes (); 278 String regNodesString = ""; for (Node n : regPoints) regNodesString += "(n" + n.getIndex() + ", " + n.getName() + ") "; 279 out.append("<td>" + regPoints.size() + (regPoints.isEmpty()? "" : "[ " + regNodesString + "]")); 280 out.append("</td>"); 281 out.append("<td>"); 282 for (Route backupRoute : r.getBackupRoutes()) 283 out.append("<a href=\"#lpProt" + backupRoute.getIndex() + "\">BU" + backupRoute.getIndex() + "</a> "); 284 out.append("</td>"); 285 boolean isOk = isOk(rsa); 286 out.append("<td bgcolor=\"" + (isOk? "PaleGreen" : "red") +"\">" + (isOk? "Yes" : "No") + "</td>"); 287 out.append("</tr>"); 288 } 289 out.append("</table>"); 290 291 /* Per protection lightpath information */ 292 out.append("<h2><a name=\"protectionStats\"></a>PER BACKUP LIGHTPATH INFORMATION SUMMARY</h2>"); 293 out.append("<p>This table shows information for each so-called backup lightpath, that is designated as backup of one or more regular lightpaths.</p>"); 294 out.append("<table border='1'>"); 295 out.append("<tr><th><b>Lighpath Route Index #</b></th><th><b>Primary routes #</b></th><th><b>Origin node</b></th>" 296 + "<th><b>Dest. node</b></th><th><b>Trav. nodes</b></th><th><b>Length (km)</b></th><th><b>Propagation delay (ms)</b></th>" 297 + "<th><b>Num. slots</b></th><th><b>Occupied slots</b></th>" 298 + "<th><b>Wavelength conversion?</b></th><th><b>Wavelength contiguity?</b></th></th>" 299 + "<th><b>Num. regenerators (reg. nodes)</b></th><th><b>Ok?</b></th></tr>"); 300 for (Route segment : netPlan.getRoutesAreBackup(wdmLayer)) 301 { 302 WDMUtils.RSA rsa = new WDMUtils.RSA(segment , false); 303 out.append("<tr>"); 304 out.append("<td><a name=\"lpProt" + segment.getIndex() + "\">" + segment.getIndex() + " (id: " + segment.getId() + ")"+ "</a></td>"); 305 out.append("<td>"); 306 for (Route r : segment.getRoutesIAmBackup()) 307 out.append("<a href=\"#lp" + r.getIndex() + "\">L" + r.getIndex() + "</a> "); 308 out.append("</td>"); 309 out.append("<td>" + printNode(segment.getIngressNode()) + "</td>"); 310 out.append("<td>" + printNode(segment.getEgressNode()) + "</td>"); 311 out.append("<td>" + seqNodesString(segment.getSeqLinks()) + "</td>"); 312 out.append("<td>" + df_2.format(segment.getLengthInKm()) + "</td>"); 313 out.append("<td>" + df_2.format(segment.getPropagationDelayInMiliseconds()) + "</td>"); 314 out.append("<td>" + rsa.getNumSlots() + "</td>"); 315 out.append("<td>" + occupiedSlotsString(rsa) + "</td>"); 316 out.append("<td>" + rsa.hasFrequencySlotConversions() + "</td>"); 317 out.append("<td>" + rsa.isFrequencySlotContiguous () + "</td>"); 318 List<Node> regPoints = rsa.getSignalRegenerationNodes (); 319 320 out.append("<td>" + regPoints.size() + (regPoints.isEmpty()? "" : "(" + regPoints + ")")); 321 out.append("</td>"); 322 boolean isOk = isOk(rsa); 323 out.append("<td bgcolor=\"" + (isOk? "PaleGreen" : "red") +"\">" + (isOk? "Yes" : "No") + "</td>"); 324 out.append("</tr>"); 325 } 326 out.append("</table>"); 327 328 329 /* Per OADM information */ 330 out.append("<h2><a name=\"nodeStats\"></a>PER OADM NODE INFORMATION SUMMARY</h2>"); 331 out.append("<p>This table shows information for each Optical Add/Drop Multiplexer (OADM) node in the network.</p>"); 332 out.append("<table border='1'>"); 333 out.append("<tr><th><b>OADM # and name</b></th><th><b>Num. input fibers</b></th><th><b>Num. output fibers</b></th>" 334 + "<th><b>Num. add lps total (reg/backup)</b></th><th><b>Num. drop lps total (reg/prot)</b></th><th><b>Num. express lps total (reg/backup)</b></th>" 335 + "<th><b>Num. signal regenerators total (reg/prot)</b></th>" 336 + "<th><b>Num. slot conversions total (reg/prot)</b></th></tr>"); 337 for (Node n : netPlan.getNodes()) 338 { 339 final int addRegLps = (int) n.getOutgoingRoutes().stream ().filter(e -> !e.isBackupRoute()).count(); 340 final int dropRegLps = (int) n.getIncomingRoutes().stream ().filter(e -> !e.isBackupRoute()).count(); 341 final int expressRegLps = (int) n.getAssociatedRoutes().stream ().filter(e -> !e.isBackupRoute()).count() - addRegLps - dropRegLps; 342 final int addBackupLps = n.getOutgoingRoutes().size() - addRegLps; 343 final int dropBackupLps = n.getIncomingRoutes().size() - dropRegLps; 344 final int expressBackupLps = (int) n.getAssociatedRoutes().stream ().filter(e -> e.isBackupRoute()).count() - addBackupLps - dropBackupLps; 345 List<Route> lists = stat.regOccupInfo.get(n); 346 final int regenRegLp = lists == null? 0 : (int) lists.stream().filter(e -> !e.isBackupRoute()).count(); 347 final int regenProtLp = lists == null? 0 : (int) lists.stream().filter(e -> e.isBackupRoute()).count(); 348 int wcRegLp = 0; 349 for (Route r : n.getAssociatedRoutes().stream().filter(e -> !e.isBackupRoute()).collect(Collectors.toSet())) 350 for (Node nReg : stat.mapRoute2RSA.get(r).getNodesWithFrequencySlotConversion()) if (n == nReg) wcRegLp ++; 351 int wcBackupLp = 0; 352 for (Route r : n.getAssociatedRoutes().stream().filter(e -> e.isBackupRoute()).collect(Collectors.toSet())) 353 for (Node nReg : stat.mapRoute2RSA.get(r).getNodesWithFrequencySlotConversion()) if (n == nReg) wcBackupLp ++; 354 out.append("<tr>"); 355 out.append("<td><a name=\"node" + n.getIndex() + "\">n" + n.getIndex() + " (" + n.getName() + ")" + "</a></td>"); 356 out.append("<td>" + n.getIncomingLinks().size() + "</td>"); 357 out.append("<td>" + n.getOutgoingLinks().size() + "</td>"); 358 out.append("<td>" + (addRegLps+addBackupLps) + "(" + addRegLps + " / " + addBackupLps + ")" + "</td>"); 359 out.append("<td>" + (dropRegLps+dropBackupLps) + "(" + dropRegLps + " / " + dropBackupLps + ")" + "</td>"); 360 out.append("<td>" + (expressRegLps+expressBackupLps) + "(" + expressRegLps + " / " + expressBackupLps + ")" + "</td>"); 361 out.append("<td>" + (regenProtLp+regenRegLp) + "(" + regenRegLp + " / " + regenProtLp + ")" + "</td>"); 362 out.append("<td>" + (wcRegLp+wcBackupLp) + "(" + wcRegLp + " / " + wcBackupLp + ")" + "</td>"); 363 } 364 out.append("</table>"); 365 366 367 out.append("</body></html>"); 368 return out.toString(); 369 } 370 371 372 private boolean isOk (WDMUtils.RSA rsa) 373 { 374 int counterLink = 0; 375 for (Link e : rsa.seqLinks) 376 { 377 for (int contS = 0; contS < rsa.getNumSlots() ; contS ++) 378 { 379 final int s = rsa.seqFrequencySlots_se.get(contS , counterLink); 380 if (s >= WDMUtils.getFiberNumFrequencySlots(e)) return false; 381 final int numLps = stat.slotOccupInfo.containsKey(Pair.of(e,s))? stat.slotOccupInfo.get(Pair.of(e,s)).size() : 0; 382 if (numLps > 1) return false; 383 } 384 counterLink ++; 385 } 386 return true; 387 } 388 389 private static String occupiedSlotsString (WDMUtils.RSA rsa) 390 { 391 if (!rsa.hasFrequencySlotConversions() && rsa.isFrequencySlotContiguous ()) return rsa.seqFrequencySlots_se.get(0,0) + "-" +rsa.seqFrequencySlots_se.get(rsa.getNumSlots()-1,0); 392 String res = ""; 393 for (int e = 0 ; e < rsa.seqFrequencySlots_se.rows() ; e ++) 394 { 395 res += "<p>"; 396 for (int s = 0 ; s < rsa.getNumSlots() ; s ++) res += rsa.seqFrequencySlots_se.get(e,s) + " "; 397 res += "</p>"; 398 } 399 return res; 400 } 401 402 private static class Statistics 403 { 404 private MinMaxAvCollector nodeInDegree = new MinMaxAvCollector (); 405 private MinMaxAvCollector nodeOutDegree = new MinMaxAvCollector (); 406 private int numberOfSignalRegenerators = 0; 407 private int numberOfWavelengthConversions = 0; 408 private int maxNumberSlots; 409 private boolean bidirectionalLinks; 410 private boolean bidirectionalDemands; 411 private boolean bidirectionalRoutes; 412 private boolean bidirectionalProtectionSegments; 413 private MinMaxAvCollector numberFrequencySlotsPerLink = new MinMaxAvCollector (); 414 private boolean unicastRoutingBifurcated; 415 private MinMaxAvCollector linkUtilization = new MinMaxAvCollector (); 416 private MinMaxAvCollector lpLengthKm = new MinMaxAvCollector (); 417 private MinMaxAvCollector lpLengthHops = new MinMaxAvCollector (); 418 private MinMaxAvCollector lpLengthMs = new MinMaxAvCollector (); 419 private MinMaxAvCollector fiberCapacityOccupiedByBackupRoutes = new MinMaxAvCollector (); 420 private Map<Pair<Link,Integer>,List<Route>> slotOccupInfo = null; 421 private Map<Node,List<Route>> regOccupInfo = null; 422 private Map<Route,WDMUtils.RSA> mapRoute2RSA = new HashMap<> (); 423 424 425 private Statistics (NetPlan netPlan , NetworkLayer wdmLayer) 426 { 427 for (Node n : netPlan.getNodes()) 428 { 429 nodeInDegree.add(n.getIncomingLinks(wdmLayer).size()); 430 nodeOutDegree.add(n.getOutgoingLinks(wdmLayer).size()); 431 } 432 bidirectionalLinks = GraphUtils.isWeightedBidirectional(netPlan.getNodes() , netPlan.getLinks(wdmLayer) , netPlan.getVectorLinkCapacity(wdmLayer)); 433 bidirectionalDemands = GraphUtils.isWeightedBidirectional(netPlan.getNodes() , netPlan.getDemands(wdmLayer) , netPlan.getVectorDemandOfferedTraffic(wdmLayer)); 434 bidirectionalRoutes = GraphUtils.isWeightedBidirectional(netPlan.getNodes() , netPlan.getRoutes (wdmLayer) , netPlan.getVectorRouteCarriedTraffic(wdmLayer)); 435 for (Link e : netPlan.getLinks(wdmLayer)) 436 { 437 numberFrequencySlotsPerLink.add((double) WDMUtils.getFiberNumFrequencySlots(e)); 438 linkUtilization.add(e.getOccupiedCapacity()); 439 fiberCapacityOccupiedByBackupRoutes.add(e.getOccupiedCapacityOnlyBackupRoutes()); 440 } 441 unicastRoutingBifurcated = false; 442 for (Demand d : netPlan.getDemands(wdmLayer)) 443 if (d.getRoutes().size() > 1) { unicastRoutingBifurcated = false; break; } 444 for (Route r : netPlan.getRoutes(wdmLayer)) 445 { 446 lpLengthHops.add(r.getNumberOfHops()); 447 lpLengthKm.add(r.getLengthInKm()); 448 lpLengthMs.add(r.getPropagationDelayInMiliseconds()); 449 } 450 this.maxNumberSlots = (int) WDMUtils.getVectorFiberNumFrequencySlots(netPlan).getMaxLocation() [0]; 451 Pair<Map<Pair<Link,Integer>,List<Route>> , Map<Node,List<Route>>> pair = WDMUtils.getNetworkSlotOccupancyMap(netPlan , false); 452 this.slotOccupInfo = pair.getFirst(); 453 this.regOccupInfo = pair.getSecond(); 454 for (Node n : netPlan.getNodes()) 455 { 456 List<Route> lists = regOccupInfo.get(n); 457 numberOfSignalRegenerators += (lists == null? 0 : lists.size()); 458 } 459 460 for (Route lp : netPlan.getRoutesAreNotBackup(wdmLayer)) 461 { 462 WDMUtils.RSA rsa = new WDMUtils.RSA(lp , false); 463 numberOfWavelengthConversions += rsa.getNodesWithFrequencySlotConversion().size(); 464 mapRoute2RSA.put(lp , rsa); 465 } 466 for (Route lp : netPlan.getRoutesAreBackup(wdmLayer)) 467 { 468 WDMUtils.RSA rsa = new WDMUtils.RSA(lp , false); 469 numberOfWavelengthConversions += rsa.getNodesWithFrequencySlotConversion().size(); 470 mapRoute2RSA.put(lp , rsa); 471 } 472// for (ProtectionSegment lp : netPlan.getProtectionSegments()) 473// { 474// WDMUtils.RSA rsa = new WDMUtils.RSA(lp); 475// numberOfWavelengthConversions += rsa.getNodesWithFrequencySlotConversion().size(); 476// protLpRSA.add(rsa); 477// } 478 } 479 480 } 481 482 private String seqNodesString(List<Link> seqLinks) 483 { 484 if (seqLinks.isEmpty()) return ""; 485 String st = "[ " + printNode(seqLinks.get(0).getOriginNode()); 486 for (Link e : seqLinks) 487 st += " -> " + printNode(e.getDestinationNode()); 488 return st + " ]"; 489 } 490 491 private static String printNode (Node n) { return "<a href=\"#node" + n.getIndex() + "\">n" + n.getIndex() + " (" + n.getName() + ")</a>"; } 492 493 private static class MinMaxAvCollector 494 { 495 private double min, max, accum; 496 private int numSamples; 497 MinMaxAvCollector () { min = 0; max = 0; accum = 0; numSamples = 0; } 498 void add (double sample) { min = numSamples == 0? sample : Math.min(min,sample); max = numSamples == 0? sample : Math.max(max,sample); accum += sample; numSamples ++; } 499 double getAv () { return numSamples == 0? 0 : accum/numSamples; } 500 public String toString () { return min + " / " + getAv() + " / " + max; } 501 public String toString (DecimalFormat df) { return df.format(min) + " / " + df.format(getAv()) + " / " + df.format(max); } 502 } 503}