using HeuristicLab.BioBoost.Data; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using System; using System.Linq; using HeuristicLab.BioBoost.Representation; using HeuristicLab.BioBoost.Utils; namespace HeuristicLab.BioBoost.Evaluators { [StorableClass] [Item("FeedstockCostEvaluator", @"Calculates all feedstock costs for known products, for which both Potentials and Utilizations are available. The intermedate results are vectors of amounts and costs per product and region and a final output named Cost for each product.")] public class FeedstockCostEvaluator : BioBoostEvaluator { #region Construction & Cloning [StorableConstructor] protected FeedstockCostEvaluator(bool isDeserializing) : base(isDeserializing) { } protected FeedstockCostEvaluator(FeedstockCostEvaluator original, Cloner cloner) : base(original, cloner) { } public FeedstockCostEvaluator() { } public override IDeepCloneable Clone(Cloner cloner) { return new FeedstockCostEvaluator(this, cloner); } #endregion /// /// foreach product with both potential and utilization calculate /// amounts = potential*utilization /// costs = amounts*price*penalty(utilization) /// cost = sum(costs) /// public override IOperation Apply() { foreach (var p in ProblemData.Products) { var totalProductCost = 0d; var potentials = GetFromProblemData(LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(p.Label)); var utilizations = GetFromScope(LayerDescriptor.Utilizations.NameWithPrefix(p.Label)); if (potentials == null || utilizations == null) continue; var utilizationsEffective = (DoubleArray)utilizations.Clone(); var length = Math.Min(potentials.Length, utilizations.Length); var amountsAtSource = new DoubleArray(length); var feedstockCosts = new DoubleArray(length); // price/supply curve quadr. for utilization > 0.5 for (var i = 0; i < length; i++) { var regionName = ProblemData.LocationNames[i]; var amount = potentials[i] * utilizations[i]; if (amount < 100) { // TODO: make this configurable utilizationsEffective[i] = 0; amount = 0; } amountsAtSource[i] = amount; var cost = GetScaledCost( p.GetRegionalBasePrice(regionName), p.GetRegionalMaxPrice(regionName), amount, utilizations[i]); feedstockCosts[i] = cost; totalProductCost += cost; } PutInScope(LayerDescriptor.UtilizationsEffective.NameWithPrefix(p.Label), utilizationsEffective, false); PutInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(p.Label), amountsAtSource, true); PutInScope(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(p.Label) , feedstockCosts, false); PutInScope(LayerDescriptor.RelativeCostAtSource.NameWithPrefix(p.Label), feedstockCosts.Zip(amountsAtSource, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false); AddCost(LayerDescriptor.AcquisitionCosts.NameWithPrefix(p.Label), totalProductCost); AddInScope(LayerDescriptor.LocalAddedValue.Name, (DoubleArray)feedstockCosts.Clone(), false); } return base.Apply(); } public static double GetScaledCost(double basePrice, double maxPrice, double amount, double utilization) { if (utilization > 0.5) { var priceDifference = maxPrice - basePrice; return amount*(priceDifference*Math.Pow((utilization - 0.5)*2, 2) + basePrice); } else { return amount*basePrice; } } } }