/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package userGeneratedContent.simulatorPlugIns.plugins.plotType; import java.util.Arrays; import staticContent.evaluation.simulator.Simulator; import staticContent.evaluation.simulator.annotations.property.BoolSimulationProperty; import staticContent.evaluation.simulator.annotations.property.StringSimulationProperty; import staticContent.evaluation.simulator.core.statistics.ResultSet; import staticContent.evaluation.simulator.core.statistics.aggregator.Aggregator; import staticContent.evaluation.simulator.core.statistics.plotEngine.PlotScript; import staticContent.evaluation.simulator.core.statistics.postProcessor.PostProcessor; import staticContent.framework.util.Util; import userGeneratedContent.simulatorPlugIns.pluginRegistry.PlotType; import userGeneratedContent.simulatorPlugIns.pluginRegistry.StatisticsType; import userGeneratedContent.simulatorPlugIns.pluginRegistry.StatisticsType.Unit; public class LineChartPlotterCf extends Plotter { @BoolSimulationProperty(name = "Calculate average", key = "CALC_AVG_OF_RUNS", inject = "1:PLOTTYPE,Plottype", isStatic = true) private final boolean CALC_AVG_OF_RUNS; @BoolSimulationProperty(name = "Inverse plot", key = "IS_INVERSE", inject = "2:PLOTTYPE,Plottype", isStatic = true) private final boolean IS_INVERSE; @StringSimulationProperty(name = "Overwritable parameters", key = "OVERWRITABLE_PARAMETERS", inject = "3:PLOTTYPE,Plottype", isStatic = true) private final String OVERWRITABLE_PARAMETERS = ""; @StringSimulationProperty(name = "None overwritable parameters", key = "NONE_OVERWRITABLE_PARAMETERS", inject = "4:PLOTTYPE,Plottype", isStatic = true) private final String NONE_OVERWRITABLE_PARAMETERS = ""; public LineChartPlotterCf() { this.CALC_AVG_OF_RUNS = Simulator.settings.getPropertyAsBoolean("CALC_AVG_OF_RUNS"); this.IS_INVERSE = Simulator.settings.getPropertyAsBoolean("IS_INVERSE"); } @Override public void plot(ResultSet resultSet) { for (String plotName:resultSet.getDesiredPlots(PlotType.LINE_CHART_CF)) { // for each plot (= diagram to display) StatisticsType[] desiredEvaluations = resultSet.getDesiredEvaluations(plotName); this.checkValidity(desiredEvaluations); PlotScript plotScript = new PlotScript(plotName, resultSet); int runs = resultSet.getNumberOfValidationRuns()+1; String aggregatorDescription; // create results for each plot line: (StatisticsType->varying_value->run) int linesInPlot = ((resultSet.getNumberOfValidationRuns() == 0) || this.CALC_AVG_OF_RUNS) ? desiredEvaluations.length * resultSet.ep.values.length : desiredEvaluations.length * resultSet.ep.values.length * runs; double[][] results = new double[linesInPlot][]; String[] lineTitles = new String[linesInPlot]; int plotLineCtr = -1; for (StatisticsType statisticsType:desiredEvaluations) { // for each StatisticsType aggregatorDescription = (statisticsType.sourceValueAggregator == Aggregator.NONE) ? "" : statisticsType.sourceValueAggregator.name() +" "; for (int i=0; i<resultSet.ep.values.length; i++) { // for each varying_value this.checkValidity(statisticsType, resultSet, i); if (runs == 1) { // no validation runs lineTitles[++plotLineCtr] = aggregatorDescription +", " +statisticsType; if (resultSet.ep.values.length != 1) { lineTitles[plotLineCtr] += " " +"(x=" +resultSet.ep.values[i] +")"; } results[plotLineCtr] = resultSet.getResultArray(i, statisticsType, 0).toNativeArray(); results[plotLineCtr] = this.performPostProcessing(results[plotLineCtr], statisticsType, resultSet, i); } else { // validation runs if (this.CALC_AVG_OF_RUNS) { // calc avg of all runs lineTitles[++plotLineCtr] = aggregatorDescription +", " +statisticsType; if (resultSet.ep.values.length != 1) { lineTitles[plotLineCtr] += " " +"(x=" +resultSet.ep.values[i] +")"; } double[][] resultsOfAllRuns = new double[runs][]; double[] avgResults = new double[resultSet.getResultArray(i, statisticsType, 0).size()]; for (int j=0; j<runs; j++) { resultsOfAllRuns[j] = resultSet.getResultArray(i, statisticsType, j).toNativeArray(); } for (int j=0; j<avgResults.length; j++) { // calc avg double sum = 0d; for (int k=0; k<runs; k++) { sum += resultsOfAllRuns[k][j]; } avgResults[j] = sum / runs; } results[plotLineCtr] = this.performPostProcessing(avgResults, statisticsType, resultSet, i); } else { // !CALC_AVG_OF_RUNS -> plot a line for each run for (int j=0; j<runs; j++) { lineTitles[++plotLineCtr] = aggregatorDescription +", " +statisticsType; if (resultSet.ep.values.length != 1) { lineTitles[plotLineCtr] += " " +"(x=" +resultSet.ep.values[i] +")"; } lineTitles[plotLineCtr] += ", RUN " +(j+1); results[plotLineCtr] = resultSet.getResultArray(i, statisticsType, j).toNativeArray(); results[plotLineCtr] = this.performPostProcessing(results[plotLineCtr], statisticsType, resultSet, i); } } } } } // write results to result.txt: StringBuffer resultFileContent = new StringBuffer(10000); for (int i=0; i<results[0].length; i++) { // note that all arrays are of the same length if (this.IS_INVERSE) { for (double[] result : results) { resultFileContent.append(decimalFormat.format(result[i]) +" " +decimalFormat.format(1d-((double)(i+1)/result.length)) +" "); } } else { for (double[] result : results) { resultFileContent.append(decimalFormat.format(result[i]) +" " +decimalFormat.format((double)(i+1)/result.length) +" "); } } resultFileContent.append("\n"); } resultFileContent.append("\n"); plotScript.writeDataFileToDisk(resultFileContent.toString()); // create plotscript: if (resultSet.ep.values.length != 1) { plotName += " - effect of " + resultSet.ep.propertyToVary +"(x)"; } if ((resultSet.getNumberOfValidationRuns() > 0) && this.CALC_AVG_OF_RUNS) { plotName += " (AVG of " +runs +" runs)"; } plotScript.setTitle(plotName); plotScript.setXlabel(desiredEvaluations[0].unitAsString); plotScript.setYlabel("Cumulative fraction"); plotScript.setScale(desiredEvaluations[0].plotScale); String plotCommand = "plot"; int columnCounter = 0; for (String lineTitle : lineTitles) { plotCommand += " varInputFile using " +(++columnCounter) +":" + (++columnCounter) + " w l lw 4 title '" +lineTitle + "',"; } plotScript.setPlotCommand(plotCommand); plotScript.writePlotScriptToDisk(); plotScript.plot(); } } private void checkValidity(StatisticsType statisticsType, ResultSet resultSet, int varyingValueId) { if (statisticsType.sourceAggregators[0] != Aggregator.NONE) { System.err.println("WARNING: PlotType.LINE_CHART_CF does not support source aggregators " + "(not possible for CF), but a SourceAggregator is specified for " +statisticsType + ".Will ignore the specified SourceAggregator."); statisticsType.sourceAggregators[0] = Aggregator.AVG; } if (!resultSet.containsData(varyingValueId, statisticsType, 0)) { System.err.println("WARNING: No results recorded for " +statisticsType +".\nWill set result to 0.0."); } } private void checkValidity(StatisticsType[] desiredEvaluations) { String lastDataType = null; for (StatisticsType st: desiredEvaluations) { if (lastDataType == null) { lastDataType = st.unitAsString; } else { if (!lastDataType.equals(st.unitAsString)) { throw new RuntimeException("ERROR: PlotType.LINE_CHART_CF " + "requires all lines of a plot to have the same data " + "type (unitAsString). " +st +" in plot " +st.destinationPlot +" has a different type. Make " + "sure to set it to " +lastDataType +", or select " + "another destinationPlot for " +st +" in StatisticsType.java."); } } } } private int lengthOfLast = Util.NOT_SET; private double[] performPostProcessing(double[] values, StatisticsType statisticsType, ResultSet resultSet, int varyingValueId) { if (this.lengthOfLast == Util.NOT_SET) { this.lengthOfLast = values.length; } else if (this.lengthOfLast != values.length) { throw new RuntimeException("ERROR: LineChartPlotterAbsCf cannot plot cf-lines " + "for StatisticsTypes with result sets of different size. Select another " + "destinationPlot for StatisticsType " +statisticsType +" in StatisticsType.java" + "\nFurther, make sure that no PostProcessor is selected, that depends on the " + "PROPERTY_TO_VARY (e.g. don't vary the number of users when the desired plot " + "shall display results PER_CLIENT)"); } Arrays.sort(values); // sort is always required for (int k=0; k<values.length; k++) { values[k] = this.performPostProcessing(values[k], statisticsType, resultSet, varyingValueId, 0); } return values; } private double performPostProcessing(double value, StatisticsType statisticsType, ResultSet resultSet, int varyingValueId, int runId) { if (statisticsType.postProcessors[0] != PostProcessor.NONE) { for (PostProcessor pp:statisticsType.postProcessors) { if (pp == PostProcessor.SORT) { continue; } value = pp.process(value, resultSet, varyingValueId, runId); } } if (statisticsType.unit == Unit.kbyte) { value = value / 1024d; } else if (statisticsType.unit == Unit.mbyte) { value = value / (1024d * 1024d); } else if (statisticsType.unit == Unit.gbyte) { value = value / (1024d * 1024d * 1024d); } else if (statisticsType.unit == Unit.sec) { value = value / 1000d; } return value; } }