/// <summary>
        /// Creates, populates and exports a plot that shows the
        /// * produced amounts
        /// * satisfied demands by source (current production or from inventory)
        /// * remaining inventory at the end of a period.
        /// </summary>
        /// <param name="solvedClspModel">It is assumed that <see cref="CapacitatedLotsizingModel.Model"/> is solved and the Solution values are written to the Variables.</param>
        public static void CreateAndExportLotSizingPlot(CapacitatedLotsizingModel solvedClspModel)
        {
            var plotModel = CreatePlottingCanvas();

            AddProducedAmountToPlot(solvedClspModel, plotModel);
            AddDemandSatisfactionToPlot(solvedClspModel, plotModel);
            AddRemainStorageToPlot(solvedClspModel, plotModel);

            ExportPlot(plotModel);
        }
        private static void AddProducedAmountToPlot(CapacitatedLotsizingModel clspModel, PlotModel oxyPlot)
        {
            var currentProduction = clspModel.PeriodInformation.Select(pi => new ColumnItem(clspModel.x[pi].Value)).ToList();

            var productionSeries = new ColumnSeries()
            {
                Title     = "Current Production",
                FillColor = OxyColor.FromRgb(byte.Parse("165"), byte.Parse("185"), byte.Parse("79"))
            };

            productionSeries.Items.AddRange(currentProduction);
            oxyPlot.Series.Add(productionSeries);
        }
        private static void AddRemainStorageToPlot(CapacitatedLotsizingModel clspModel, PlotModel oxyPlot)
        {
            var dataPoints = clspModel.PeriodInformation.Select(pi => new ColumnItem(clspModel.s[pi].Value)).ToList();

            var series = new ColumnSeries()
            {
                Title     = "Remaining Inventory",
                FillColor = OxyColor.FromRgb(byte.Parse("82"), byte.Parse("35"), byte.Parse("152"))
            };

            series.Items.AddRange(dataPoints);
            oxyPlot.Series.Add(series);
        }
        /// <summary>
        /// The main method
        /// </summary>
        /// <param name="args">
        /// no arguments required
        /// </param>
        static void Main(string[] args)
        {
            // create time steps with their "name", demand, setup cost,
            // production cost per unit, inventory cost per unit
            var csv = new CsvReader(File.OpenText("timesteps.csv"));

            csv.Configuration.Delimiter   = ";";
            csv.Configuration.CultureInfo = new CultureInfo("en-US");
            var periodInformation = csv.GetRecords <PeriodInformation>();

            // use default settings
            var config = new Configuration
            {
                NameHandling            = NameHandlingStyle.Manual,
                ComputeRemovedVariables = true
            };

            using (var scope = new ModelScope(config))
            {
                // create a model, based on given data and the model scope
                var clspModel = new CapacitatedLotsizingModel(periodInformation);

                var solverCfg = new GurobiSolverConfiguration()
                {
                    ModelOutputFile = new FileInfo("clsp.lp"),
                };

                // Get a solver instance, change your solver
                var solver = new GurobiSolver(solverCfg);

                // solve the model
                var solution = solver.Solve(clspModel.Model);

                // print objective and variable decisions
                Console.WriteLine($"{solution.ObjectiveValues.Single()}");
                clspModel.y.Variables.ForEach(x => Console.WriteLine($"{x.ToString().PadRight(36)}: {x.Value}"));
                clspModel.x.Variables.ForEach(y => Console.WriteLine($"{y.ToString().PadRight(36)}: {y.Value}"));
                clspModel.s.Variables.ForEach(s => Console.WriteLine($"{s.ToString().PadRight(36)}: {s.Value}"));

                clspModel.Model.VariableStatistics.WriteCSV(AppDomain.CurrentDomain.BaseDirectory);

                PlottingUtils.CreateAndExportLotSizingPlot(clspModel);
            }

            Console.ReadLine();
        }
        private static void AddDemandSatisfactionToPlot(CapacitatedLotsizingModel clspModel, PlotModel oxyPlot)
        {
            var usedStorage    = new List <ColumnItem>();
            var usedProduction = new List <ColumnItem>();

            foreach (var currentPeriod in clspModel.PeriodInformation)
            {
                var endStorage     = clspModel.s[currentPeriod].Value;
                var producedAmount = clspModel.x[currentPeriod].Value;
                // basically represents the flow conservation constraint
                var initialStorage = -producedAmount + endStorage + currentPeriod.Demand;

                // split bar item in 2 sections.
                var demandFromStorage    = Math.Min(initialStorage, currentPeriod.Demand);
                var demandFromProduction = Math.Min(currentPeriod.Demand - demandFromStorage, producedAmount);
                usedStorage.Add(new ColumnItem(demandFromStorage));
                usedProduction.Add(new ColumnItem(demandFromProduction));
            }

            var storageSeries = new ColumnSeries()
            {
                Title      = "Demand from Inventory",
                IsStacked  = true,
                StackGroup = "DemandSatisfaction",
                FillColor  = OxyColor.FromRgb(byte.Parse("132"), byte.Parse("122"), byte.Parse("178"))
            };

            storageSeries.Items.AddRange(usedStorage);

            var productionSeries = new ColumnSeries()
            {
                Title      = "Demand from Production",
                IsStacked  = true,
                StackGroup = "DemandSatisfaction",
                FillColor  = OxyColor.FromRgb(byte.Parse("245"), byte.Parse("174"), byte.Parse("78"))
            };

            productionSeries.Items.AddRange(usedProduction);

            oxyPlot.Series.Add(storageSeries);
            oxyPlot.Series.Add(productionSeries);
        }