#region License Information
/* HeuristicLab
* Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab 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.
*
* HeuristicLab 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 HeuristicLab. If not, see .
*/
#endregion
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;
using HEAL.Attic;
namespace HeuristicLab.BioBoost.Evaluators {
[StorableType("A2DAA8F7-71AB-48F8-B019-CF14FB34A979")]
[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(StorableConstructorFlag _) : base(_) { }
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;
}
}
}
}