/******************************************************************************* * Copyright (c) 2013-2015 Pablo Pavon-Marino, Jose-Luis Izquierdo-Zaragoza. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Pablo Pavon-Marino, Jose-Luis Izquierdo-Zaragoza - initial API and implementation ******************************************************************************/ package com.net2plan.examples.onlineSim.resilience; import cern.jet.random.tdouble.AbstractDoubleDistribution; import cern.jet.random.tdouble.DoubleUniform; import cern.jet.random.tdouble.Exponential; import cern.jet.random.tdouble.engine.MersenneTwister64; import com.net2plan.interfaces.networkDesign.Net2PlanException; import com.net2plan.interfaces.networkDesign.NetPlan; import com.net2plan.interfaces.simulation.IEventGenerator; import com.net2plan.interfaces.simulation.SimAction; import com.net2plan.interfaces.simulation.SimEvent; import com.net2plan.libraries.SRGUtils; import com.net2plan.utils.RandomUtils; import com.net2plan.utils.Triple; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.Set; import java.util.TreeSet; import org.apache.commons.lang3.mutable.MutableLong; /** * Generates random failures in SRGs according to a random process with an exponential distribution with MTTF and MTTR mean values. * * @author Pablo Pavon-Marino, Jose-Luis Izquierdo-Zaragoza * @version 1.1, May 2015 */ public class NRSim_EG_exponentialSRGFailureGenerator extends IEventGenerator { private Map upPeriodDurationInHours_srg; private Map downPeriodDurationInHours_srg; private Set srgsDown_previousState; private long[] srgIds; private AbstractDoubleDistribution randomSRGId; private boolean simultaneousFailures; private double maxSimultaneousFailures; private double lastEventTime, transitoryTime; private double[] histogram_accum; private long numSimulatedFailures; private Map simulatedFailures_srg; @Override public final String finish(StringBuilder output, double simTime) { output.append("
"); output.append(""); for (Entry entry : simulatedFailures_srg.entrySet()) output.append(String.format("", entry.getKey(), entry.getValue().longValue())); output.append(String.format("", numSimulatedFailures)); output.append("
Table I. Per-SRG failure distribution
SRG# failures
%d%d
Total: %d
"); for (int i = 0; i <= maxSimultaneousFailures; i++) output.append(String.format("", i, 100 * histogram_accum[i] / (simTime - transitoryTime))); output.append("
Table II. Network state distribution
Simultaneous failuresPercentage of time (%)
%d%.3f
"); return "Failure/reparation event generator statistics"; } @Override public final void finishTransitory(double simTime) { numSimulatedFailures = 0; Arrays.fill(histogram_accum, 0); transitoryTime = simTime; lastEventTime = simTime; maxSimultaneousFailures = srgsDown_previousState.size(); for(MutableLong value : simulatedFailures_srg.values()) value.setValue(0); } @Override public String getDescription() { return "Generates random failures in SRGs according to a random process with an exponential distribution with MTTF and MTTR mean values."; } @Override public List> getParameters() { List> parameters = new LinkedList>(); parameters.add(Triple.of("randomSeed", "-1", "Seed for the random generator (-1 means random)")); parameters.add(Triple.of("defaultMTTFInHours", "8748", "Default value for Mean Time To Fail (hours) (unused when failureModel=SRGfromNetPlan)")); parameters.add(Triple.of("defaultMTTRInHours", "12", "Default value for Mean Time To Repair (hours) (unused when failureModel=SRGfromNetPlan)")); parameters.add(Triple.of("failureModel", "#select# perBidirectionalLinkBundle SRGfromNetPlan perNode perLink perDirectionalLinkBundle", "Failure model selection: SRGfromNetPlan, perNode, perLink, perDirectionalLinkBundle, perBidirectionalLinkBundle")); parameters.add(Triple.of("simultaneousFailures", "#boolean# true", "Indicates whether each SRG may fail independently of each other, or only an SRG can fail at the same time (in this case MTTF and MTTR must be the same for all SRGs")); return parameters; } @Override public void initialize(NetPlan initialNetPlan, NetPlan currentNetPlan, Map algorithmParameters, Map simulationParameters, Map net2planParameters) { simultaneousFailures = Boolean.parseBoolean(algorithmParameters.get("simultaneousFailures")); long seed = Long.parseLong(algorithmParameters.get("randomSeed")); if (seed == -1) seed = RandomUtils.random(0, Long.MAX_VALUE - 1); Random seedGenerator = new Random(seed); double defaultMTTFInHours, defaultMTTRInHours; try { defaultMTTFInHours = Double.parseDouble(algorithmParameters.get("defaultMTTFInHours")); if (defaultMTTFInHours <= 0) defaultMTTFInHours = Double.MAX_VALUE; } catch (Throwable ex) { throw new Net2PlanException("Parameter 'defaultMTTFInHours' value must be a valid number"); } try { defaultMTTRInHours = Double.parseDouble(algorithmParameters.get("defaultMTTRInHours")); if (defaultMTTRInHours <= 0) throw new Exception("Bad"); } catch (Exception ex) { throw new Net2PlanException("Parameter 'defaultMTTRInHours' value must be greater than zero"); } String failureModel = algorithmParameters.get("failureModel"); switch (failureModel) { case "SRGfromNetPlan": break; case "perNode": SRGUtils.configureSRGs(currentNetPlan, defaultMTTFInHours, defaultMTTRInHours, SRGUtils.SharedRiskModel.PER_NODE, true); break; case "perLink": SRGUtils.configureSRGs(currentNetPlan, defaultMTTFInHours, defaultMTTRInHours, SRGUtils.SharedRiskModel.PER_LINK, true); break; case "perDirectionalLinkBundle": SRGUtils.configureSRGs(currentNetPlan, defaultMTTFInHours, defaultMTTRInHours, SRGUtils.SharedRiskModel.PER_DIRECTIONAL_LINK_BUNDLE, true); break; case "perBidirectionalLinkBundle": SRGUtils.configureSRGs(currentNetPlan, defaultMTTFInHours, defaultMTTRInHours, SRGUtils.SharedRiskModel.PER_BIDIRECTIONAL_LINK_BUNDLE, true); break; default: throw new Net2PlanException("Failure model not valid. Please, check algorithm parameters description"); } int numSRGs = currentNetPlan.getNumberOfSRGs(); if (numSRGs == 0) throw new Net2PlanException("No SRGs were defined"); srgIds = currentNetPlan.getSRGIdsVector(); numSimulatedFailures = 0; maxSimultaneousFailures = 0; histogram_accum = new double[numSRGs + 1]; upPeriodDurationInHours_srg = new LinkedHashMap(); downPeriodDurationInHours_srg = new LinkedHashMap(); srgsDown_previousState = new LinkedHashSet(); simulatedFailures_srg = new LinkedHashMap(); if (simultaneousFailures) { for (long srgId : srgIds) { double mttf = currentNetPlan.getSRGMeanTimeToFailInHours(srgId); double mttr = currentNetPlan.getSRGMeanTimeToRepairInHours(srgId); upPeriodDurationInHours_srg.put(srgId, new Exponential(1 / mttf, new MersenneTwister64(seedGenerator.nextInt()))); downPeriodDurationInHours_srg.put(srgId, new Exponential(1 / mttr, new MersenneTwister64(seedGenerator.nextInt()))); simulatedFailures_srg.put(srgId, new MutableLong()); } for (long srgId : srgIds) scheduleNewFailureAndReparation(srgId, 0); } else { double mttf = currentNetPlan.getSRGMeanTimeToFailInHours(srgIds[0]); double mttr = currentNetPlan.getSRGMeanTimeToRepairInHours(srgIds[0]); AbstractDoubleDistribution upPeriodDurationInHours = new Exponential(1 / mttf, new MersenneTwister64(seedGenerator.nextInt())); AbstractDoubleDistribution downPeriodDurationInHours = new Exponential(1 / mttr, new MersenneTwister64(seedGenerator.nextInt())); for (long srgId : srgIds) { if (Math.abs(currentNetPlan.getSRGMeanTimeToFailInHours(srgId) - mttf) > 1E-10) throw new Net2PlanException("When 'simultaneousFailures=false', all SRGs must have the same MTTF"); if (Math.abs(currentNetPlan.getSRGMeanTimeToRepairInHours(srgId) - mttr) > 1E-10) throw new Net2PlanException("When 'simultaneousFailures=false', all SRGs must have the same MTTR"); upPeriodDurationInHours_srg.put(srgId, upPeriodDurationInHours); downPeriodDurationInHours_srg.put(srgId, downPeriodDurationInHours); simulatedFailures_srg.put(srgId, new MutableLong()); } randomSRGId = new DoubleUniform(0, numSRGs - 1, new MersenneTwister64(seedGenerator.nextInt())); long srgId = srgIds[randomSRGId.nextInt()]; scheduleNewFailureAndReparation(srgId, 0); } lastEventTime = 0; transitoryTime = 0; } @Override public void processEvent(NetPlan currentNetPlan, SimEvent event) { Object eventObject = event.getEventObject(); double simTime = event.getEventTime(); histogram_accum[srgsDown_previousState.size()] += simTime - lastEventTime; if (eventObject instanceof SRGUp) { long srgId = ((SRGUp) eventObject).srgId; currentNetPlan.activateActionMonitoring(); Set nodesDown2Up = new TreeSet(currentNetPlan.getSRGNodes(srgId)); for(long srgId_previousState : srgsDown_previousState) { if (srgId_previousState == srgId) continue; nodesDown2Up.removeAll(currentNetPlan.getSRGNodes(srgId_previousState)); } for(long nodeId : nodesDown2Up) currentNetPlan.setNodeUp(nodeId); Set layerIds = currentNetPlan.getLayerIds(); for(long layerId : layerIds) { Set linksDown2Up_thisLayer = new TreeSet(currentNetPlan.getSRGLinks(layerId, srgId)); for(long srgId_previousState : srgsDown_previousState) { if (srgId_previousState == srgId) continue; linksDown2Up_thisLayer.removeAll(currentNetPlan.getSRGLinks(layerId, srgId_previousState)); } for(long linkId : linksDown2Up_thisLayer) currentNetPlan.setLinkUp(layerId, linkId); } srgsDown_previousState.remove(srgId); if (simultaneousFailures) { scheduleNewFailureAndReparation(srgId, simTime); } else { long newSRGId = srgIds[randomSRGId.nextInt()]; scheduleNewFailureAndReparation(newSRGId, simTime); } List actions = currentNetPlan.getActionsPerformed(); if (actions.isEmpty()) return; scheduleEvent(new SimEvent(simTime, actions, SimEvent.DestinationModule.EVENT_PROCESSOR)); } else if (eventObject instanceof SRGDown) { if (!simultaneousFailures && !srgsDown_previousState.isEmpty()) throw new RuntimeException("Bad"); numSimulatedFailures++; long srgId = ((SRGDown) eventObject).srgId; simulatedFailures_srg.get(srgId).increment(); srgsDown_previousState.add(srgId); currentNetPlan.activateActionMonitoring(); currentNetPlan.setSRGDown(srgId); List actions = currentNetPlan.getActionsPerformed(); if (actions.isEmpty()) return; scheduleEvent(new SimEvent(simTime, actions, SimEvent.DestinationModule.EVENT_PROCESSOR)); } maxSimultaneousFailures = Math.max(maxSimultaneousFailures, srgsDown_previousState.size()); lastEventTime = simTime; } private void scheduleNewFailureAndReparation(long srgId, double simTime) { double nextSRGFailureTime = simTime + 3600 * upPeriodDurationInHours_srg.get(srgId).nextDouble(); double nextSRGReparationTime = nextSRGFailureTime + 3600 * downPeriodDurationInHours_srg.get(srgId).nextDouble(); scheduleEvent(new SimEvent(nextSRGFailureTime, new SRGDown(srgId), SimEvent.DestinationModule.EVENT_GENERATOR)); scheduleEvent(new SimEvent(nextSRGReparationTime, new SRGUp(srgId), SimEvent.DestinationModule.EVENT_GENERATOR)); } /** * Class representing a 'SRGDown' event. * * @since 1.1 */ public static class SRGDown { private final long srgId; private SRGDown(long srgId) { this.srgId = srgId; } @Override public String toString() { return "SRG " + srgId + " becomes down"; } } /** * Class representing a 'SRGUp' event. * * @since 1.1 */ public static class SRGUp { private final long srgId; private SRGUp(long srgId) { this.srgId = srgId; } @Override public String toString() { return "SRG " + srgId + " becomes up"; } } }