/******************************************************************************* * 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.timeVaryingTraffic; import com.net2plan.interfaces.networkDesign.Net2PlanException; import com.net2plan.interfaces.networkDesign.NetPlan; import com.net2plan.interfaces.simulation.IEventGenerator; import com.net2plan.interfaces.simulation.SimEvent; import com.net2plan.libraries.TrafficMatrixGenerationModels; import com.net2plan.utils.DoubleUtils; import com.net2plan.utils.Pair; import com.net2plan.utils.RandomUtils; import com.net2plan.utils.Triple; import java.text.SimpleDateFormat; import java.util.*; /** *

This class modifies the offered traffic volume per demand according to an * activity function (see [1]) with respect to the * timezone.

* *

The timezone of each node is represented as the time offset respecting to * Coordinated Universal Time (UTC) and it is between -12 and 12.

* * @see [1] J. Milbrandt, M. Menth, S. Kopf, "Adaptive Bandwidth Allocation: Impact of Traffic Demand Models for Wide Area Networks," University of Würzburg, Germany, Report No. 363, June 2005 * * @author Pablo Pavon-Marino, Jose-Luis Izquierdo-Zaragoza * @version 1.1, May 2015 */ public class TVSim_EG_activityFunction extends IEventGenerator { private final static String DATE_FORMAT = "MM/dd/YY HH:mm:ss"; private Set nodeIds, demandIds; private Map> demandMap; private Map h_d; private Calendar calendar; private Random r; private double sigma; private double threshold; private double timeGranularityInSeconds; private Map timezones; private double lastSimTime; @Override public String getDescription() { StringBuilder description = new StringBuilder(); description.append("This class modifies the offered traffic volume per demand according to an activity function."); return description.toString(); } @Override public List> getParameters() { List> parameters = new LinkedList>(); parameters.add(Triple.of("defaultTimezone", "0", "Default timezone with respect to UTC (in range [-12, 12])")); parameters.add(Triple.of("sigma", "0.05", "Standard deviation from normalized peak traffic")); parameters.add(Triple.of("threshold", "0.25", "Maximum variation of the random noise")); parameters.add(Triple.of("randomSeed", "-1", "Seed for the random generator (-1 means random)")); parameters.add(Triple.of("startDate", new SimpleDateFormat(DATE_FORMAT).format(Calendar.getInstance().getTime()), "Initial date and time of the simulation")); return parameters; } @Override public void initialize(NetPlan initialNetPlan, NetPlan currentNetPlan, Map algorithmParameters, Map simulationParameters, Map net2planParameters) { long seed = Long.parseLong(algorithmParameters.get("randomSeed")); if (seed == -1) seed = RandomUtils.random(0, Long.MAX_VALUE - 1); r = new Random(seed); int defaultTimezone = Integer.parseInt(algorithmParameters.get("defaultTimezone")); if (defaultTimezone < -12 || defaultTimezone > 12) throw new Net2PlanException("'defaultTimezone' must be in range [-12, 12]"); try { String startDate = algorithmParameters.get("startDate"); calendar = Calendar.getInstance(); calendar.setTime(new SimpleDateFormat(DATE_FORMAT).parse(startDate)); } catch(Throwable e) { throw new Net2PlanException("Wrong 'startDate' value"); } sigma = Double.parseDouble(algorithmParameters.get("sigma")); if (sigma < 0) throw new Net2PlanException("'sigma' must be a non-negative number"); threshold = Double.parseDouble(algorithmParameters.get("threshold")); if (threshold < 0) throw new Net2PlanException("'threshold' must be a non-negative number"); timeGranularityInSeconds = Double.parseDouble(algorithmParameters.get("timeGranularityInSeconds")); if (timeGranularityInSeconds <= 0) throw new Net2PlanException("'timeGranularityInSeconds' must be greater than zero"); lastSimTime = 0; nodeIds = initialNetPlan.getNodeIds(); demandIds = initialNetPlan.getDemandIds(); demandMap = initialNetPlan.getDemandMap(); h_d = initialNetPlan.getDemandOfferedTrafficMap(); timezones = DoubleUtils.constantMap(nodeIds, defaultTimezone); for(long nodeId : nodeIds) { String str_timezone = initialNetPlan.getNodeAttribute(nodeId, "timezone"); if (str_timezone == null) continue; double timezone = Double.parseDouble(str_timezone); if (timezone < -12 || timezone > 12) throw new Net2PlanException(String.format("Timezone for node %d must be in range [-12, 12]", nodeId)); timezones.put(nodeId, timezone); } scheduleEvent(new SimEvent(timeGranularityInSeconds, new WakeUpEvent(), SimEvent.DestinationModule.EVENT_GENERATOR)); } @Override public void processEvent(NetPlan currentNetPlan, SimEvent event) { if (!(event.getEventObject() instanceof WakeUpEvent)) return; double simTime = event.getEventTime(); calendar.add(Calendar.MILLISECOND, (int) ((simTime - lastSimTime) * 1000)); int hours = calendar.get(Calendar.HOUR_OF_DAY); int minutes = calendar.get(Calendar.MINUTE); int seconds = calendar.get(Calendar.SECOND); int weekday = calendar.get(Calendar.DAY_OF_WEEK); double UTC = hours + (double) minutes / 60 + (double) seconds / 3600; Map activityFactor = new LinkedHashMap(); double peakTrafficFactor = weekday == Calendar.SATURDAY || weekday == Calendar.SUNDAY ? 0.5 : 1; for (long nodeId : nodeIds) activityFactor.put(nodeId, TrafficMatrixGenerationModels.activityFactor(UTC, timezones.get(nodeId), 0.3, peakTrafficFactor)); currentNetPlan.activateActionMonitoring(); for (long demandId : demandIds) { long ingressNodeId = demandMap.get(demandId).getFirst(); long egressNodeId = demandMap.get(demandId).getSecond(); double activityFactorNodePair = (activityFactor.get(ingressNodeId) + activityFactor.get(egressNodeId)) / 2; double variation = r.nextGaussian() * sigma; if (variation > threshold) variation = threshold; else if (variation < -threshold) variation = -threshold; activityFactorNodePair += variation; if (activityFactorNodePair < 0) activityFactorNodePair = 0; currentNetPlan.setDemandOfferedTraffic(demandId, h_d.get(demandId) * activityFactorNodePair); } scheduleEvent(new SimEvent(simTime, currentNetPlan.getActionsPerformed(), SimEvent.DestinationModule.EVENT_PROCESSOR)); scheduleEvent(new SimEvent(simTime + timeGranularityInSeconds, event.getEventObject(), SimEvent.DestinationModule.EVENT_GENERATOR)); lastSimTime = simTime; } private static class WakeUpEvent { @Override public String toString() { return "Wake-up event"; } } }