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 019package com.net2plan.examples.ocnbook.onlineSim; 020 021import cern.colt.matrix.tdouble.DoubleFactory1D; 022import cern.colt.matrix.tdouble.DoubleMatrix1D; 023import cern.jet.random.tdouble.Exponential; 024import com.net2plan.interfaces.networkDesign.*; 025import com.net2plan.interfaces.simulation.IEventGenerator; 026import com.net2plan.interfaces.simulation.SimEvent; 027import com.net2plan.libraries.SRGUtils; 028import com.net2plan.libraries.TrafficMatrixGenerationModels; 029import com.net2plan.utils.InputParameter; 030import com.net2plan.utils.Pair; 031import com.net2plan.utils.RandomUtils; 032import com.net2plan.utils.Triple; 033 034import java.text.SimpleDateFormat; 035import java.util.*; 036 037/** 038 * Generates events to a technology-agnostic network, consisting of connection requests/releases and failures and repairs. 039 * 040 * The events generated targeted to the event processor module (e.g. {@code Online_evProc_generalProcessor}) are: 041 * <ul> 042 * <li>SimEvent.RouteAdd: To add a route to the network, associated to a given demand (the demand is seen as a source of connection requests).</li> 043 * <li>SimEvent.RouteRemove: If the processor successfully creates a Route object, as a reaction to the RouteAdd event, then a RouteRemove event will be sent to the processor, to release the resources when the connection holding time ends. In the incremental model, route remove events are never sent</li> 044 * <li>SimEvent.DemandModify: Sends this event to ask the processor to modify the offered traffic of a demand (recall that generators cannot modify the NetPlan object). The demand offered traffic is the average traffic of connection requests created. This generator changes it to be able to simulate fast and slow traffic fluctuations.</li> 045 * <li>SimEvent.NodesAndLinksChangeFailureState: Sends these events to the processor, representing network failures and repairs to react to.</li> 046 * </ul> 047 * 048 * The average rate of connection requests sent can change along time using fast and/or slow fluctuations. Fast fluctuations are intended to reflect typical short time-scale 049 * traffic variations, while slow fluctuation are more suitable for representing multihour (slow) traffic fluctuations (e.g. night vs day traffic). 050 * 051 * In the long-run simulations, connections have a finite holding time, so route add and route remove events can be sent. 052 * With the incremental model, connections are never released, and the traffic only increases. This can be used e.g. in studies that search for the moment in 053 * which the network needs an upgrade, since its capacity is exhausted. 054 * 055 * @net2plan.keywords CAC (Connection-Admission-Control), Network recovery: protection, Network recovery: restoration 056 * @net2plan.ocnbooksections Section 3.3.3, Exercise 3.7, Exercise 3.8 057 * @net2plan.inputParameters 058 * @author Pablo Pavon-Marino 059 */ 060public class Online_evGen_generalGenerator extends IEventGenerator 061{ 062 private final static String DATE_FORMAT = "MM/dd/YY HH:mm:ss"; 063 064 private InputParameter _fail_failureModel = new InputParameter ("_fail_failureModel", "#select# perBidirectionalLinkBundle none SRGfromNetPlan perNode perLink perDirectionalLinkBundle" , "Failure model selection: SRGfromNetPlan, perNode, perLink, perDirectionalLinkBundle, perBidirectionalLinkBundle"); 065 private InputParameter _tfFast_fluctuationType = new InputParameter ("_tfFast_fluctuationType", "#select# none random-truncated-gaussian" , ""); 066 private InputParameter _trafficType = new InputParameter ("_trafficType", "#select# non-connection-based connection-based-longrun connection-based-incremental " , ""); 067 private InputParameter _tfSlow_fluctuationType = new InputParameter ("_tfSlow_fluctuationType", "#select# none time-zone-based" , ""); 068 private InputParameter cac_arrivalsPattern = new InputParameter ("cac_arrivalsPattern", "#select# deterministic random-exponential-arrivals-deterministic-duration random-exponential-arrivals-and-duration" , ""); 069 private InputParameter trafficLayerId = new InputParameter ("trafficLayerId", (long) -1 , "Layer containing traffic demands (-1 means default layer)"); 070 private InputParameter randomSeed = new InputParameter ("randomSeed", (long) 1 , "Seed for the random generator (-1 means random)"); 071 private InputParameter cac_avHoldingTimeHours = new InputParameter ("cac_avHoldingTimeHours", (double) 1 , "Default average connection duration (in seconds)" , 0 , false , Double.MAX_VALUE , true); 072 private InputParameter cac_defaultConnectionSizeTrafficUnits = new InputParameter ("cac_defaultConnectionSizeTrafficUnits", (double) 1 , "Default requested traffic volume per connection" , 0 , false , Double.MAX_VALUE , true); 073 private InputParameter tfFast_timeBetweenDemandFluctuationsHours = new InputParameter ("tfFast_timeBetweenDemandFluctuationsHours", (double) 0.1 , "Average time between two changes of demand offered traffic in a demand (demands behave independently)" , 0 , false , Double.MAX_VALUE , true); 074 private InputParameter tfFast_fluctuationCoefficientOfVariation = new InputParameter ("tfFast_fluctuationCoefficientOfVariation", (double) 1.0 , "Average time between two changes of demand offered traffic in a demand (demands behave independently)" , 0 , false , Double.MAX_VALUE , true); 075 private InputParameter tfFast_maximumFluctuationRelativeFactor = new InputParameter ("tfFast_maximumFluctuationRelativeFactor", (double) 1.0 , "The fluctuation of a demand cannot exceed this percentage from the media" , 0 , true , Double.MAX_VALUE , true); 076 private InputParameter tfSlow_startDate = new InputParameter ("tfSlow_startDate", new SimpleDateFormat(DATE_FORMAT).format(Calendar.getInstance().getTime()) , "Initial date and time of the simulation"); 077 private InputParameter tfSlow_timeBetweenDemandFluctuationsHours = new InputParameter ("tfSlow_timeBetweenDemandFluctuationsHours", (double) 1.0 , "Average time between two changes of demand offered traffic in a demand (demands behave independently)" , 0 , false , Double.MAX_VALUE , true); 078 private InputParameter tfSlow_defaultTimezone = new InputParameter ("tfSlow_defaultTimezone", (int) 0 , "Default timezone with respect to UTC (in range [-12, 12])" , -12 , 12); 079 private InputParameter fail_defaultMTTFInHours = new InputParameter ("fail_defaultMTTFInHours", (double) 10 , "Default value for Mean Time To Fail (hours) (unused when failureModel=SRGfromNetPlan)" , 0 , false , Double.MAX_VALUE , true); 080 private InputParameter fail_defaultMTTRInHours = new InputParameter ("fail_defaultMTTRInHours", (double) 12 , "Default value for Mean Time To Repair (hours) (unused when failureModel=SRGfromNetPlan)" , 0 , false , Double.MAX_VALUE , true); 081 private InputParameter fail_statisticalPattern = new InputParameter ("fail_statisticalPattern", "#select# exponential-iid" , "Type of failure and repair statistical pattern"); 082 083 /* demands and links do not change the number (maybe capacity, offered traffic...) */ 084 private Random rng; 085 private DoubleMatrix1D cac_avHoldingTimeSeconds_d , cac_connectionSize_d; 086 private DoubleMatrix1D currentTheoreticalOfferedTraffic_d; 087 private boolean cac_auxIATDeterministic , cac_auxIATExponential , cac_auxDurationDeterministic , cac_auxDurationExponential , cac_auxIncremental; 088 private boolean isCac; 089 private boolean tfFast_auxRandomGaussian; 090 private DoubleMatrix1D initialOfferedTraffic_d; // the offered traffic is the sum of the two 091 private DoubleMatrix1D slowChangingOfferedTraffic_d; // the offered traffic is the sum of the two 092 private DoubleMatrix1D tfSlow_timeZones_n; 093 private Calendar tfSlow_calendar; 094 private double tfSlow_simTimeOfLastCalendarUpdate; 095 private boolean tfSlow_auxTimeZoneBased; 096 private Set<Pair<SimEvent.RouteAdd,Double>> cacIncremental_potentiallyBlockedRouteRequests; 097 098 private Set<SharedRiskGroup> fail_currentlyFailedSRGs; 099 100 public Online_evGen_generalGenerator () { super (); } 101 102 @Override 103 public String getDescription() 104 { 105 return "Generates events to a technology-agnostic network, consisting of connection requests/releases and failures and repairs."; 106 } 107 108 @Override 109 public List<Triple<String, String, String>> getParameters() 110 { 111 /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */ 112 return InputParameter.getInformationAllInputParameterFieldsOfObject(this , "com.net2plan.examples.ocnbook.onlineSim.Online_evGen_generalGenerator"); 113 } 114 115 @Override 116 public void initialize(NetPlan initialNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters) 117 { 118 /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */ 119 InputParameter.initializeAllInputParameterFieldsOfObject(this , "com.net2plan.examples.ocnbook.onlineSim.Online_evGen_generalGenerator" , algorithmParameters); 120 121 NetworkLayer trafficLayer = trafficLayerId.getLong () == -1? initialNetPlan.getNetworkLayerDefault () : initialNetPlan.getNetworkLayerFromId(trafficLayerId.getLong ()); 122 if (trafficLayer == null) throw new Net2PlanException ("Unknown layer id"); 123 final int D = initialNetPlan.getNumberOfDemands(trafficLayer); 124 final int N = initialNetPlan.getNumberOfNodes (); 125 if (D == 0) throw new Net2PlanException("No demands were defined in the original design"); 126 127 if (randomSeed.getLong () == -1) randomSeed.initialize((long) RandomUtils.random(0, Long.MAX_VALUE - 1)); 128 this.rng = new Random(randomSeed.getLong ()); 129 this.initialOfferedTraffic_d = initialNetPlan.getVectorDemandOfferedTraffic(trafficLayer); 130 this.currentTheoreticalOfferedTraffic_d = initialNetPlan.getVectorDemandOfferedTraffic(trafficLayer); 131 this.isCac = (_trafficType.getString ().equalsIgnoreCase("connection-based-longrun") || _trafficType.getString ().equalsIgnoreCase("connection-based-incremental")); 132 /* Initialize CAC if applicable */ 133 if (isCac) 134 { 135 this.cac_auxIATDeterministic = cac_arrivalsPattern.getString ().equalsIgnoreCase("deterministic"); 136 this.cac_auxIATExponential = cac_arrivalsPattern.getString ().equalsIgnoreCase("random-exponential-arrivals-deterministic-duration") || cac_arrivalsPattern.getString ().equalsIgnoreCase("random-exponential-arrivals-and-duration"); 137 this.cac_auxDurationDeterministic = cac_arrivalsPattern.getString ().equalsIgnoreCase("deterministic") || cac_arrivalsPattern.getString ().equalsIgnoreCase("random-exponential-arrivals-deterministic-duration"); 138 this.cac_auxDurationExponential = cac_arrivalsPattern.getString ().equalsIgnoreCase("random-exponential-arrivals-and-duration"); 139 this.cac_auxIncremental = _trafficType.getString ().equalsIgnoreCase("connection-based-incremental"); 140 this.cac_avHoldingTimeSeconds_d = DoubleFactory1D.dense.make (D , 0); 141 this.cac_connectionSize_d = DoubleFactory1D.dense.make (D , 0); 142 this.cacIncremental_potentiallyBlockedRouteRequests = cac_auxIncremental? new HashSet<Pair<SimEvent.RouteAdd,Double>> () : null; 143 for (Demand originalDemand : initialNetPlan.getDemands(trafficLayer)) 144 { 145 final int d = originalDemand.getIndex(); 146 final double connectionSize = (originalDemand.getAttribute("connectionSize") != null)? Double.parseDouble(originalDemand.getAttribute("connectionSize")) : cac_defaultConnectionSizeTrafficUnits.getDouble(); 147 final double holdingTimeSeconds = (originalDemand.getAttribute("holdingTime") != null)? Double.parseDouble(originalDemand.getAttribute("holdingTime")) : cac_avHoldingTimeHours.getDouble() * 3600; 148 final double avIATSeconds = connectionSize * holdingTimeSeconds / currentTheoreticalOfferedTraffic_d.get(d); 149 final double nextInterArrivalTimeSeconds = cac_auxIATDeterministic? avIATSeconds : cac_auxIATExponential? Exponential.staticNextDouble(1/avIATSeconds) : -1; 150 cac_avHoldingTimeSeconds_d.set (d,holdingTimeSeconds); 151 cac_connectionSize_d.set (d,connectionSize); 152 scheduleEvent(new SimEvent(nextInterArrivalTimeSeconds, SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateConnectionRequest(originalDemand))); 153 } 154 } 155 156 /* Initialize fast changing traffic */ 157 this.tfFast_auxRandomGaussian = false; 158 if (_tfFast_fluctuationType.getString ().equalsIgnoreCase("random-truncated-gaussian")) 159 { 160 this.tfFast_auxRandomGaussian = true; 161 for (Demand originalDemand : initialNetPlan.getDemands(trafficLayer)) 162 scheduleEvent(new SimEvent(0, SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateDemandOfferedTrafficFastFluctuation(originalDemand))); 163 } 164 165 /* Initialize slow changing traffic */ 166 this.slowChangingOfferedTraffic_d = initialNetPlan.getVectorDemandOfferedTraffic(trafficLayer); // the offered traffic is the sum of the two 167 if (_tfSlow_fluctuationType.getString ().equalsIgnoreCase("time-zone-based")) 168 { 169 this.tfSlow_auxTimeZoneBased = true; 170 this.tfSlow_calendar = Calendar.getInstance(); 171 try { this.tfSlow_calendar.setTime(new SimpleDateFormat(DATE_FORMAT).parse(tfSlow_startDate.getString())); } catch (Exception e) { e.printStackTrace(); throw new Net2PlanException ("Error parsing the date"); } 172 this.tfSlow_simTimeOfLastCalendarUpdate = 0; 173 tfSlow_timeZones_n = DoubleFactory1D.dense.make (N , tfSlow_defaultTimezone.getInt()); 174 for(Node node : initialNetPlan.getNodes ()) 175 { 176 if (node.getAttribute("timezone") == null) continue; 177 double timezone = Double.parseDouble(node.getAttribute("timezone")); 178 if (timezone < -12 || timezone > 12) throw new Net2PlanException(String.format("Timezone for node %d must be in range [-12, 12]", node.getIndex ())); 179 tfSlow_timeZones_n.set(node.getIndex (), timezone); 180 } 181 for (Demand demand : initialNetPlan.getDemands(trafficLayer)) 182 scheduleEvent(new SimEvent(0.0, SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateDemandOfferedTrafficSlowFluctuation(demand))); 183 } 184 185 /* Initialize slow changing traffic */ 186 if (!_fail_failureModel.getString ().equalsIgnoreCase("none")) 187 { 188 this.fail_currentlyFailedSRGs = new HashSet<SharedRiskGroup> (); 189 if (!fail_statisticalPattern.getString ().equalsIgnoreCase("exponential-iid")) throw new Net2PlanException ("Unknown failure statisitical pattern"); 190 switch (_fail_failureModel.getString ()) 191 { 192 case "SRGfromNetPlan": 193 break; 194 case "perNode": 195 SRGUtils.configureSRGs(initialNetPlan, fail_defaultMTTFInHours.getDouble(), fail_defaultMTTRInHours.getDouble(), SRGUtils.SharedRiskModel.PER_NODE, true); 196 break; 197 case "perLink": 198 SRGUtils.configureSRGs(initialNetPlan, fail_defaultMTTFInHours.getDouble(), fail_defaultMTTRInHours.getDouble(), SRGUtils.SharedRiskModel.PER_LINK, true); 199 break; 200 case "perDirectionalLinkBundle": 201 SRGUtils.configureSRGs(initialNetPlan, fail_defaultMTTFInHours.getDouble(), fail_defaultMTTRInHours.getDouble(), SRGUtils.SharedRiskModel.PER_DIRECTIONAL_LINK_BUNDLE, true); 202 break; 203 case "perBidirectionalLinkBundle": 204 SRGUtils.configureSRGs(initialNetPlan, fail_defaultMTTFInHours.getDouble(), fail_defaultMTTRInHours.getDouble(), SRGUtils.SharedRiskModel.PER_BIDIRECTIONAL_LINK_BUNDLE, true); 205 break; 206 default: 207 throw new Net2PlanException("Failure model not valid. Please, check algorithm parameters description"); 208 } 209 if (initialNetPlan.getNumberOfSRGs() == 0) throw new Net2PlanException("No SRGs were defined"); 210 for (SharedRiskGroup srg : initialNetPlan.getSRGs()) 211 { 212 final double nextEvent = Exponential.staticNextDouble(1 / srg.getMeanTimeToFailInHours()); 213// System.out.println ("nextEvent: " + nextEvent +", srg.getMeanTimeToFailInHours(): " + srg.getMeanTimeToFailInHours()); 214 scheduleEvent(new SimEvent(nextEvent , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateFailureSRG(srg))); 215 } 216 } 217 218 219 } 220 221 @Override 222 public void processEvent(NetPlan currentNetPlan, SimEvent event) 223 { 224 final double simTime = event.getEventTime(); 225 Object eventObject = event.getEventObject(); 226 227 /* if a connection could not be setup, end simulation in the incremental simulation mode */ 228 if (this.cac_auxIncremental) 229 { 230 for (Pair<SimEvent.RouteAdd,Double> ev : new LinkedList<Pair<SimEvent.RouteAdd,Double>> (this.cacIncremental_potentiallyBlockedRouteRequests)) 231 { 232 if (ev.getFirst().routeAddedToFillByProcessor != null) 233 cacIncremental_potentiallyBlockedRouteRequests.remove(ev); 234 else if (ev.getSecond() < simTime) endSimulation(); // not assigned route, and it is in the past => end simulation in the incremental mode 235 } 236 } 237 238 if (eventObject instanceof GenerateConnectionRequest) 239 { 240 final GenerateConnectionRequest connectionRequest = (GenerateConnectionRequest) eventObject; 241 final Demand demand = connectionRequest.demand; 242 final int d = demand.getIndex (); 243 final double h_d = currentTheoreticalOfferedTraffic_d.get(d); // same traffic units as connection size 244 final double avHoldingTimeSeconds = cac_avHoldingTimeSeconds_d.get(d); 245 final double connectionSize = cac_connectionSize_d.get (d); 246 final double avIATSeconds = connectionSize * avHoldingTimeSeconds / h_d; 247 final double nextHoldingTimeSeconds = cac_auxDurationDeterministic? avHoldingTimeSeconds : cac_auxDurationExponential? Exponential.staticNextDouble(1/avHoldingTimeSeconds) : -1; 248 final double nextInterArrivalTimeSeconds = cac_auxIATDeterministic? avIATSeconds : cac_auxIATExponential? Exponential.staticNextDouble(1/avIATSeconds) : -1; 249 250 /* Events to the processor. RouteAdd, and if not incremental mode, route remove */ 251 SimEvent.RouteAdd routeInfo_add = new SimEvent.RouteAdd(demand , null , connectionSize , connectionSize); 252 scheduleEvent(new SimEvent (simTime, SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , routeInfo_add)); 253 if (cac_auxIncremental) 254 this.cacIncremental_potentiallyBlockedRouteRequests.add (Pair.of(routeInfo_add,simTime)); // to check later if it was blocked 255 else 256 scheduleEvent(new SimEvent(simTime + nextHoldingTimeSeconds, SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateConnectionRelease(routeInfo_add))); 257 258 /* Event for me: new connection */ 259 scheduleEvent(new SimEvent(simTime + nextInterArrivalTimeSeconds, SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateConnectionRequest(demand))); 260 } 261 if (eventObject instanceof GenerateConnectionRelease) 262 { 263 final GenerateConnectionRelease releaseEvent = (GenerateConnectionRelease) eventObject; 264// SimEvent.DemandModify demandOfferedTrafficUpdate = new SimEvent.DemandModify(releaseEvent.routeAddEvent.demand , -releaseEvent.routeAddEvent.carriedTraffic , true); 265// scheduleEvent(new SimEvent (simTime, SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , demandOfferedTrafficUpdate)); 266 if (releaseEvent.routeAddEvent.routeAddedToFillByProcessor != null) 267 { 268 SimEvent.RouteRemove routeInfo_remove = new SimEvent.RouteRemove(releaseEvent.routeAddEvent.routeAddedToFillByProcessor); 269 scheduleEvent(new SimEvent (simTime , SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , routeInfo_remove)); 270 } 271 } 272 else if (eventObject instanceof GenerateDemandOfferedTrafficFastFluctuation) 273 { 274 final GenerateDemandOfferedTrafficFastFluctuation trafficFluctuation = (GenerateDemandOfferedTrafficFastFluctuation) eventObject; 275 final Demand demand = trafficFluctuation.demand; 276 final int d = demand.getIndex (); 277 final double slowChangingTrafficPart = slowChangingOfferedTraffic_d.get(d); 278 if (tfFast_auxRandomGaussian) 279 { 280 double newFastTrafficVariation = rng.nextGaussian() * tfFast_fluctuationCoefficientOfVariation.getDouble() * slowChangingTrafficPart; 281 newFastTrafficVariation = Math.max (newFastTrafficVariation , slowChangingTrafficPart * (1 - tfFast_maximumFluctuationRelativeFactor.getDouble())); 282 newFastTrafficVariation = Math.min (newFastTrafficVariation , slowChangingTrafficPart * (1 + tfFast_maximumFluctuationRelativeFactor.getDouble())); 283 currentTheoreticalOfferedTraffic_d.set (d , slowChangingTrafficPart + newFastTrafficVariation); 284 if (!isCac) // inform the processor with a demand modified only if it is NOT cac. In CAC the sent events are the routes only, and the algorithms update the offered traffic according to it 285 { 286 SimEvent.DemandModify modifyEvent = new SimEvent.DemandModify(demand , Math.max (0 , slowChangingTrafficPart + newFastTrafficVariation) , false); 287 scheduleEvent(new SimEvent (simTime, SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , modifyEvent)); 288 } 289 } 290 else if (_tfFast_fluctuationType.getString ().equalsIgnoreCase("none")) 291 { 292 throw new RuntimeException ("Bad"); 293 } 294 else throw new Net2PlanException ("Unknow fast traffic fluctuation type: " + _tfFast_fluctuationType.getString ()); 295 /* Send event to me for the next fast change */ 296 scheduleEvent(new SimEvent(simTime + tfFast_timeBetweenDemandFluctuationsHours.getDouble()*3600 , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateDemandOfferedTrafficFastFluctuation(demand))); 297 } 298 else if (eventObject instanceof GenerateDemandOfferedTrafficSlowFluctuation) 299 { 300 final GenerateDemandOfferedTrafficSlowFluctuation trafficFluctuation = (GenerateDemandOfferedTrafficSlowFluctuation) eventObject; 301 final Demand demand = trafficFluctuation.demand; 302 final int d = demand.getIndex (); 303 final double currentSlowHd = slowChangingOfferedTraffic_d.get(d); 304 final double currentHd = currentTheoreticalOfferedTraffic_d.get(d); 305 if (tfSlow_auxTimeZoneBased) 306 { 307 /* Send event to processor with the demand change */ 308 tfSlow_calendar.add(Calendar.MILLISECOND, (int) ((simTime - tfSlow_simTimeOfLastCalendarUpdate) * 1000)); 309 final int hours = tfSlow_calendar.get(Calendar.HOUR_OF_DAY); 310 final int minutes = tfSlow_calendar.get(Calendar.MINUTE); 311 final int seconds = tfSlow_calendar.get(Calendar.SECOND); 312 final int weekday = tfSlow_calendar.get(Calendar.DAY_OF_WEEK); 313 final double UTC = hours + (double) minutes / 60 + (double) seconds / 3600; 314 final double peakTrafficFactor = weekday == Calendar.SATURDAY || weekday == Calendar.SUNDAY ? 0.5 : 1; 315 final double activityOriginNode = TrafficMatrixGenerationModels.activityFactor(UTC, tfSlow_timeZones_n.get(demand.getIngressNode().getIndex ()), 0.3, peakTrafficFactor); 316 final double activityDestinationNode = TrafficMatrixGenerationModels.activityFactor(UTC, tfSlow_timeZones_n.get(demand.getEgressNode().getIndex ()), 0.3, peakTrafficFactor); 317 final double activityFactorNodePair = Math.max (0 , (activityOriginNode + activityDestinationNode) / 2); 318 final double newSlowFluctuationTraffic = initialOfferedTraffic_d.get(d) * activityFactorNodePair; 319 final double currentFastFluctuationTraffic = currentHd - currentSlowHd; 320 this.currentTheoreticalOfferedTraffic_d.set (d , newSlowFluctuationTraffic + currentFastFluctuationTraffic); 321 this.slowChangingOfferedTraffic_d.set (d , newSlowFluctuationTraffic); 322 if (!isCac) // inform the processor with a demand modified only if it is NOT cac. In CAC the sent events are the routes only, and the algorithms update the offered traffic according to it 323 { 324 SimEvent.DemandModify modifyEvent = new SimEvent.DemandModify(demand , Math.max (0 , newSlowFluctuationTraffic + currentFastFluctuationTraffic), false); 325 scheduleEvent(new SimEvent (simTime, SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , modifyEvent)); 326 } 327 tfSlow_simTimeOfLastCalendarUpdate = simTime; 328 } 329 else throw new Net2PlanException ("Unknow fast traffic fluctuation type: " + _tfFast_fluctuationType.getString ()); 330 /* Send event to me for the next fast change */ 331 scheduleEvent(new SimEvent(simTime + tfSlow_timeBetweenDemandFluctuationsHours.getDouble()*3600 , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateDemandOfferedTrafficSlowFluctuation(demand))); 332 } 333 else if (eventObject instanceof GenerateFailureSRG) 334 { 335 final GenerateFailureSRG srgEvent = (GenerateFailureSRG) eventObject; 336 final SharedRiskGroup srg = srgEvent.srg; 337 338 /* Send event of appropriate failures to the processor (only links and nodes changing its state) */ 339 Set<Node> nodesUpToDown = new HashSet<Node> (currentNetPlan.getNodesUp()); nodesUpToDown.retainAll(srg.getNodes()); 340 Set<Link> linksUpToDown = new HashSet<Link> (currentNetPlan.getLinksUpAllLayers()); linksUpToDown.retainAll(srg.getLinksAllLayers()); 341 if (!nodesUpToDown.isEmpty() || !linksUpToDown.isEmpty()) 342 { 343 SimEvent.NodesAndLinksChangeFailureState failEvent = new SimEvent.NodesAndLinksChangeFailureState (null , nodesUpToDown , null , linksUpToDown); 344 scheduleEvent(new SimEvent(simTime , SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , failEvent)); 345 } 346 /* Send repair event to myself */ 347 scheduleEvent(new SimEvent(simTime + Exponential.staticNextDouble(1 / srg.getMeanTimeToRepairInHours()) , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateRepairSRG(srg))); 348 349 fail_currentlyFailedSRGs.add (srg); 350 } 351 else if (eventObject instanceof GenerateRepairSRG) 352 { 353 final GenerateRepairSRG srgEvent = (GenerateRepairSRG) eventObject; 354 final SharedRiskGroup srg = srgEvent.srg; 355 356 /* Send event of appropriate repairs to the processor (only links and nodes changing its state) */ 357 fail_currentlyFailedSRGs.remove (srg); 358 Set<Node> nodesDownAfterRepair = new HashSet<Node> (); 359 Set<Link> linksDownAfterRepair = new HashSet<Link> (); 360 for (SharedRiskGroup srgStillFailed : fail_currentlyFailedSRGs) 361 { 362 nodesDownAfterRepair.addAll (srgStillFailed.getNodes()); 363 linksDownAfterRepair.addAll (srgStillFailed.getLinksAllLayers()); 364 } 365 Set<Node> nodesDownToUp = new HashSet<Node> (currentNetPlan.getNodesDown()); nodesDownToUp.removeAll (nodesDownAfterRepair); 366 Set<Link> linksDownToUp = new HashSet<Link> (currentNetPlan.getLinksDownAllLayers()); linksDownToUp.removeAll (linksDownAfterRepair); 367 368 if (!nodesDownToUp.isEmpty() || !linksDownToUp.isEmpty()) 369 { 370 SimEvent.NodesAndLinksChangeFailureState repairEvent = new SimEvent.NodesAndLinksChangeFailureState (nodesDownToUp , null , linksDownToUp , null); 371 scheduleEvent(new SimEvent(simTime , SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , repairEvent)); 372 } 373 /* Send repair event to myself */ 374 scheduleEvent(new SimEvent(simTime + Exponential.staticNextDouble(1 / srg.getMeanTimeToFailInHours()) , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , new GenerateFailureSRG(srg))); 375 } 376 } 377 378 379 private static class GenerateConnectionRequest 380 { 381 public final Demand demand; 382 public GenerateConnectionRequest(Demand demand) { this.demand = demand; } 383 @Override 384 public String toString() { return "Generate connection request for demand " + demand.getId (); } 385 } 386 private static class GenerateConnectionRelease 387 { 388 public final SimEvent.RouteAdd routeAddEvent; 389 public GenerateConnectionRelease(SimEvent.RouteAdd routeAddEvent) { this.routeAddEvent = routeAddEvent; } 390 @Override 391 public String toString() { return "Generate connection release for demand " + routeAddEvent.demand.getId (); } 392 } 393 private static class GenerateDemandOfferedTrafficFastFluctuation 394 { 395 public final Demand demand; 396 public GenerateDemandOfferedTrafficFastFluctuation(Demand demand) { this.demand= demand; } 397 @Override 398 public String toString() { return "Generate fast fluctuation of offered traffic of demand " + demand.getId () ; } 399 } 400 private static class GenerateDemandOfferedTrafficSlowFluctuation 401 { 402 public final Demand demand; 403 public GenerateDemandOfferedTrafficSlowFluctuation(Demand demand) { this.demand= demand; } 404 @Override 405 public String toString() { return "Generate slow fluctuation of offered traffic of demand " + demand.getId () ; } 406 } 407 private static class GenerateFailureSRG 408 { 409 public final SharedRiskGroup srg; 410 public GenerateFailureSRG(SharedRiskGroup srg) { this.srg = srg; } 411 @Override 412 public String toString() { return "Generate failure in SRG " + srg.getId () ; } 413 } 414 private static class GenerateRepairSRG 415 { 416 public final SharedRiskGroup srg; 417 public GenerateRepairSRG(SharedRiskGroup srg) { this.srg = srg; } 418 @Override 419 public String toString() { return "Generate repair event in SRG " + srg.getId () ; } 420 } 421 422}