source: branches/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ConversionCostEvaluator.cs @ 13069

Last change on this file since 13069 was 13069, checked in by gkronber, 7 years ago

#2499: imported source code for HeuristicLab.BioBoost from private repository with some changes

File size: 15.3 KB
Line 
1using System.Drawing;
2using HeuristicLab.BioBoost.Data;
3using HeuristicLab.BioBoost.Utils;
4using HeuristicLab.Common;
5using HeuristicLab.Core;
6using HeuristicLab.Data;
7using HeuristicLab.Operators;
8using HeuristicLab.Optimization;
9using HeuristicLab.Parameters;
10using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
11using System;
12using System.Collections.Generic;
13using System.Linq;
14using HeuristicLab.BioBoost.Representation;
15
16namespace HeuristicLab.BioBoost.Evaluators {
17  [StorableClass]
18  [Item("ConversionCostEvaluator", "Simulates the conversion of all applicable conversion processes.")]
19  public class ConversionCostEvaluator : BioBoostEvaluator {
20
21    #region fields
22    private DoubleArray invest, maint, fuel, labor, other;
23    #endregion
24
25    #region Construction & Cloning
26    [StorableConstructor]
27    protected ConversionCostEvaluator(bool isDeserializing) : base(isDeserializing) {}
28    protected ConversionCostEvaluator(ConversionCostEvaluator original, Cloner cloner) : base(original, cloner) { }
29    public ConversionCostEvaluator() { }
30    public override IDeepCloneable Clone(Cloner cloner) {
31      return new ConversionCostEvaluator(this, cloner);
32    }
33    #endregion
34
35    public override IOperation Apply() {
36      var conversions = ProblemData.Conversions;
37      var products = new Dictionary<string, DoubleArray>();
38      var prices = ProblemData.Products.ToDictionary(p => p.Label, p => p.Price);
39      DoubleArray productCosts = new DoubleArray(0);
40      invest = ProblemData.InvestmentCostFactors;
41      maint = ProblemData.MaintenanceCostFactors;
42      fuel = ProblemData.FuelCostFactors;
43      labor = ProblemData.LaborCostFactors;
44      other = ProblemData.OtherCostFactors;
45      foreach (var feedstock in conversions.Select(c => c.Key)) {
46        var feedstockAmounts = GetFromScope<DoubleArray>(LayerDescriptor.AmountsAtTarget.NameWithPrefix(feedstock));
47        var feedstockCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtTarget.NameWithPrefix(feedstock));
48        if (feedstockAmounts == null) continue;
49        var length = feedstockAmounts.Length;
50        var totalConversionCost = 0d;
51        var totalConstructionCost = 0d;
52        var totalOperationCost = 0d;
53        var totalStorageCost = 0d;
54        var totalScalingPenalty = 0d;
55        var totalExceedingCapacityPenalty = 0d;
56        var converterCapacities = new DoubleArray(length);
57        var maxCapacities = new DoubleArray(length);
58        var storageCapacities = new DoubleArray(length);
59        var chosenConversions = new List<Variant>(new Variant[length]);
60        if (productCosts.Length < length)
61          productCosts = new DoubleArray(length);
62        for (int i = 0; i < length; i++) {
63          var amount = feedstockAmounts[i];
64          maxCapacities[i] = conversions[feedstock].Max(c => GetMaxCapacity(c, ProblemData.LocationNames[i]));
65          if (amount <= 0) continue;
66          var chosenConversion = ChooseConversion(conversions[feedstock], amount, i);
67          if (chosenConversion != null) {
68            //feedstockAmounts[i] = 0;
69            totalConversionCost += chosenConversion.Cost;
70            totalConstructionCost += chosenConversion.ConstructionCost;
71            totalOperationCost += chosenConversion.OperationCost;
72            totalStorageCost += chosenConversion.StorageCost;
73            totalScalingPenalty += chosenConversion.ScalingPenalty;
74            totalExceedingCapacityPenalty += chosenConversion.ExceedingCapacityPenalty;
75            converterCapacities[i] = chosenConversion.Capacity;
76            storageCapacities[i] = chosenConversion.StorageCapacity;
77            AddProducts(products, chosenConversion.Conversion.Products, Math.Min(chosenConversion.Amount, chosenConversion.Capacity), i, length);
78            AddProducts(products, chosenConversion.Conversion.ConstructionEmissions, chosenConversion.Capacity/chosenConversion.Conversion.DesignCapacity, i, length);
79            chosenConversions[i] = chosenConversion;
80            feedstockCosts[i] += chosenConversion.StorageCost;
81            productCosts[i] += feedstockCosts[i] + chosenConversion.Cost + chosenConversion.ConstructionCost + chosenConversion.OperationCost; // still without side products
82          } else {
83            feedstockAmounts[i] = 0;
84          }
85        }
86        // TODO: 2. Runde?!?!?
87        //RemoveFromScope(LayerDescriptor.AmountsAtTarget.NameWithPrefix(feedstock));
88        RenameInScope(LayerDescriptor.AmountsAtTarget.NameWithPrefix(feedstock), LayerDescriptor.AmountsAtTargetConverted.NameWithPrefix(feedstock));
89        var conversionCosts = chosenConversions.Select(0, v => v.Cost).ToDoubleArray();
90        var constructionCosts = chosenConversions.Select(0, v => v.ConstructionCost).ToDoubleArray();
91        var operationCosts = chosenConversions.Select(0, v => v.OperationCost).ToDoubleArray();
92        PutInScope(LayerDescriptor.ConversionCosts.NameWithPrefix(feedstock), conversionCosts, false);
93        PutInScope(LayerDescriptor.ConversionPlantConstructionCost.NameWithPrefix(feedstock), constructionCosts, false);
94        PutInScope(LayerDescriptor.ConversionPlantOperationCost.NameWithPrefix(feedstock), operationCosts, false);
95        PutInScope(LayerDescriptor.RelativeConversionCosts.NameWithPrefix(feedstock), conversionCosts.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
96        PutInScope(LayerDescriptor.RelativeConversionPlantConstructionCosts.NameWithPrefix(feedstock), constructionCosts.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
97        PutInScope(LayerDescriptor.RelativeConversionPlantOperationCosts.NameWithPrefix(feedstock), operationCosts.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
98        var storageCosts = chosenConversions.Select(0, v => v.StorageCost).ToDoubleArray();
99        PutInScope(LayerDescriptor.StorageCost.NameWithPrefix(feedstock), storageCosts, false);
100        PutInScope(LayerDescriptor.RelativeStorageCost.NameWithPrefix(feedstock), storageCosts.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
101        var totalLogisticCost = GetFromScope<DoubleArray>(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(feedstock));
102        totalLogisticCost = totalLogisticCost.Zip(storageCosts, (l, s) => l + s).ToDoubleArray();
103        PutInScope(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(feedstock), totalLogisticCost, false);
104        PutInScope(LayerDescriptor.LogisticCostsPerTon.NameWithPrefix(feedstock), totalLogisticCost.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
105        PutInScope(LayerDescriptor.MaxConversionCapacity.NameWithPrefix(feedstock), maxCapacities, false);
106        var scalingPenalties = chosenConversions.Select(0, v => v.ScalingPenalty).ToDoubleArray();
107        var exceedingCapacityPenalties = chosenConversions.Select(0, v => v.ExceedingCapacityPenalty).ToDoubleArray();
108        PutInScope(LayerDescriptor.ScalingPenalty.NameWithPrefix(feedstock), scalingPenalties, false);
109        PutInScope(LayerDescriptor.ExceedingCapacityPenalties.NameWithPrefix(feedstock), exceedingCapacityPenalties, false);
110        AddInScope(LayerDescriptor.TotalPenalty.Name, scalingPenalties.Zip(exceedingCapacityPenalties, (s, c) => s+c).ToDoubleArray(), false);
111        PutInScope(LayerDescriptor.TotalCostsAtTarget.NameWithPrefix(feedstock), feedstockCosts, false); // now including storage costs
112        PutInScope(LayerDescriptor.RelativeCostAtTarget.NameWithPrefix(feedstock), feedstockCosts.Zip(feedstockAmounts, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
113        var totalDirectConversionCost = chosenConversions.Select(0, c => c.Cost + c.Conversion.Products.TotalCost(prices, c.Conversion.MainProduct)*c.Amount) .ToDoubleArray();
114        PutInScope(LayerDescriptor.TotalDirectConversionCost.NameWithPrefix(feedstock), totalDirectConversionCost, false);
115        //var mainProductAmounts = chosenConversions.Select((c, i) => c != null ? 0 : products[c.Conversion.MainProduct][i]).ToArray();
116        PutInScope(LayerDescriptor.RelativeTotalDirectConversionCost.NameWithPrefix(feedstock), totalDirectConversionCost.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
117        PutInScope(LayerDescriptor.ScalingFactors.NameWithPrefix(feedstock), chosenConversions.Select(0, v => v.ScalingFactor).ToDoubleArray(), false);
118        var totalAmortizedConversionCost = totalDirectConversionCost
119          // .Zip(storageCosts, (t, s) => t + s) -> included in logistic costs
120          .Zip(constructionCosts, (t, c) => t + c)
121          .Zip(operationCosts, (t, o) => t + o)
122          .ToDoubleArray();
123        PutInScope(LayerDescriptor.TotalAmortizedConversionCosts.NameWithPrefix(feedstock), totalAmortizedConversionCost, false);
124        PutInScope(LayerDescriptor.RelativeTotalAmortizedConversionCosts.NameWithPrefix(feedstock), totalAmortizedConversionCost.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
125        AddCost(LayerDescriptor.ConversionCosts.NameWithPrefix(feedstock), totalConversionCost);
126        AddCost(LayerDescriptor.ConversionPlantConstructionCost.NameWithPrefix(feedstock), totalConstructionCost);
127        AddCost(LayerDescriptor.ConversionPlantOperationCost.NameWithPrefix(feedstock), totalOperationCost);
128        AddCost(LayerDescriptor.StorageCost.NameWithPrefix(feedstock), totalStorageCost);
129        AddCost(LayerDescriptor.ScalingPenalty.NameWithPrefix(feedstock), totalScalingPenalty);
130        AddCost(LayerDescriptor.ExceedingCapacityPenalties.NameWithPrefix(feedstock), totalExceedingCapacityPenalty);
131        AddInScope(LayerDescriptor.ConverterCapacities.NameWithPrefix(feedstock), converterCapacities, false);
132        AddInScope(LayerDescriptor.StorageCapacities.NameWithPrefix(feedstock), storageCapacities, false);
133        AddInScope(LayerDescriptor.LocalAddedValue.Name, chosenConversions.Select(0, v => v.Cost + v.ConstructionCost + v.OperationCost).ToDoubleArray(), false);
134        foreach (var p in products) {
135          if (p.Value.Max() <= 0 || (prices.ContainsKey(p.Key) && prices[p.Key] <= 0)) continue; // don't report "production cost" for demands and waste products
136          var costsAtSource = new DoubleArray(productCosts.Select((c,i) => c + (chosenConversions[i] == null ? 0 : chosenConversions[i].Conversion.Products.TotalCost(prices, p.Key)*chosenConversions[i].Amount)).ToArray());
137          AddInScope(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(p.Key), costsAtSource, false);
138          costsAtSource = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(p.Key));
139          PutInScope(LayerDescriptor.RelativeCostAtSource.NameWithPrefix(p.Key), costsAtSource.Zip(p.Value, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
140        }
141      }
142      foreach (var p in products) {
143        AddInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(p.Key), p.Value, false);
144      }
145      return base.Apply();
146    }
147
148    private void AddProducts(Dictionary<string, DoubleArray> overallProducts, IEnumerable<IValueParameter> products, double amount, int i, int length) {
149      foreach (var e in products) {
150        DoubleArray values = null;
151        if (!overallProducts.TryGetValue(e.Name, out values)) {
152          overallProducts.Add(e.Name, values = new DoubleArray(length));
153        }
154        values[i] += ((DoubleValue)e.Value).Value*amount;
155      }
156    }
157
158    private class Variant : IComparable<Variant> {
159      public Conversion Conversion;
160      public double Cost;
161      public double ConstructionCost;
162      public double OperationCost;
163      public double Capacity;
164      public double StorageCost;
165      public double StorageCapacity;
166      public double Amount;
167      public double ScalingPenalty;
168      public double ExceedingCapacityPenalty;
169      public double ScalingFactor;
170
171      public int CompareTo(Variant other) {
172        return (int) (Cost - other.Cost);
173      }
174    }
175
176    private Variant ChooseConversion(IEnumerable<Conversion> conversions, double amount, int i) {
177      var variants = new List<Variant>();
178      foreach (var c in conversions) { // TODO: select best scaling variant?
179        if (amount <= 0) continue;
180        var actualAmount = amount * (1-c.DryMatterLoss);
181        var v = new Variant {Capacity = actualAmount/c.UtilizationFactor, Conversion = c};
182        var regionName = ProblemData.LocationNames[i];
183        double maxCapacity = GetMaxCapacity(c, regionName);
184        v.ExceedingCapacityPenalty = CapacityPenalty(v.Capacity, maxCapacity);
185        //if (maxCapacity <= 0) continue;
186        var availableCapacity = GetValue(c.AvailableCapacities, regionName, 0);
187        var newCapacity = Math.Max(0, v.Capacity - availableCapacity);
188        v.ScalingFactor = v.Capacity/c.DesignCapacity;
189        var minScale = c.MinCapacity/c.DesignCapacity;
190        var maxScale = maxCapacity/c.DesignCapacity;
191        v.ScalingPenalty = ScalingPenalty(v.ScalingFactor, minScale, maxScale);
192        v.ConstructionCost = ScaledCost(newCapacity/c.DesignCapacity, maxScale, c.Construction, c.ConstructionScalingExponent);
193        v.OperationCost = ScaledCost(v.ScalingFactor, maxScale, c.Maintenance, c.MaintenanceScalingExponent);
194        v.OperationCost = (newCapacity/v.Capacity)*v.OperationCost + ((v.Capacity - newCapacity)/v.Capacity)*v.OperationCost*c.AvailableMaintenanceFactor;
195        v.Cost = c.Cost*actualAmount;
196        v.Amount = actualAmount;
197        v.StorageCapacity = v.Capacity/365*c.SafetyStock;
198        v.StorageCost = GetLogisticActionCost(c.Storage, v.StorageCapacity, i);
199        variants.Add(v);
200      }
201      variants.Sort();
202      return variants.FirstOrDefault();
203    }
204
205    public static double GetMaxCapacity(Conversion c, string regionName) {
206      var maxCapacity = GetValue(c.MaxCapacities, regionName, -1);
207      if (maxCapacity < 0) maxCapacity = GetValue(c.MaxCapacities, "Default", -2);
208      return maxCapacity;
209    }
210
211    private double GetLogisticActionCost(LogisticAction a, double amount, int i) {
212      return
213        amount*a.Investment*invest[i] +
214        amount*a.Maintenance*maint[i] +
215        amount*a.Fuel*fuel[i] +
216        amount*a.Labor*labor[i] +
217        amount*a.Other*other[i];
218    }
219
220    private static double GetValue(ValueParameterCollection values, string name, double defaultValue) {
221      IValueParameter parameter;
222      if (values.TryGetValue(name, out parameter))
223        return ((DoubleValue) parameter.Value).Value;
224      return defaultValue;
225    }
226
227    public static double ScalingPenalty(double scale, double minScale, double maxScale) {
228      if (scale > maxScale)
229        return Util.Sqr(scale-maxScale);
230      if (scale < minScale)
231        return 4*(minScale - scale)*scale/Util.Sqr(minScale) * 2;
232      return 0;
233    }
234
235    public static double CapacityPenalty(double capacity, double maxCapacity) {
236      if (capacity > maxCapacity) {
237        if (maxCapacity == 0) {
238          return Math.Pow(capacity, 2);
239        } else {
240          return Math.Pow((capacity - maxCapacity)/maxCapacity, 2);
241        }
242      }
243      return 0;
244    }
245
246    public static double ScaledCost(double scale, double maxScale, double baseCost, double exponent) {
247      if (scale > 10) return baseCost*Math.Pow(10, exponent - 1);
248      return baseCost*Math.Pow(scale, exponent);
249    }
250
251  }
252}
Note: See TracBrowser for help on using the repository browser.