/*******************************************************************************
* 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"; }
}
}