source: branches/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Representation/BioBoostCompoundSolution.cs @ 13071

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

#2499: added license headers and removed unused usings

File size: 28.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Globalization;
25using System.IO;
26using System.Linq;
27using System.Runtime.InteropServices;
28using System.Text;
29using HeuristicLab.BioBoost.Evaluators;
30using HeuristicLab.BioBoost.Operators.Mutation;
31using HeuristicLab.BioBoost.ProblemDescription;
32using HeuristicLab.BioBoost.Utils;
33using HeuristicLab.Common;
34using HeuristicLab.Core;
35using HeuristicLab.Data;
36using HeuristicLab.Parameters;
37using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
38using NetTopologySuite.GeometriesGraph;
39using SharpMap;
40using SharpMap.Data.Providers;
41using SharpMap.Layers;
42using SharpMap.Utilities.Wfs;
43// using YamlDotNet.RepresentationModel.Serialization.NodeTypeResolvers;
44
45namespace HeuristicLab.BioBoost.Representation {
46  [StorableClass]
47  public sealed class BioBoostCompoundSolution : ParameterizedNamedItem, IStorableContent {
48    public class TransportInfo {
49      public string Product;
50      public int SrcRegionIdx;
51      public int DestRegionIdx;
52      public string SrcRegion;
53      public string DestRegion;
54      public string Mode;
55      public double Distance;
56      public double Amount;
57    }
58
59    [Storable]
60    public Dictionary<string, IntArray> IntValues;
61
62    [Storable]
63    public Dictionary<string, DoubleArray> DoubleValues;
64
65    [Storable]
66    public Dictionary<string, StringArray> StringValues;
67
68    [Storable]
69    public Dictionary<string, ItemArray<ItemList<IntValue>>> TransportTargets;
70
71    [Storable]
72    private BioBoostProblemData problemDataRef;
73
74    public BioBoostProblemData ProblemDataReference {
75      get { return problemDataRef; }
76      set {
77        if (problemDataRef != value) {
78          problemDataRef = value;
79          EvaluateAndUpdateAllResults(); // also raises OnSolutionChanged (re-evaluation is only done when the problem is set by an external entity)
80        }
81      }
82    }
83
84
85    #region Parameters
86    public ValueParameter<StringArray> LocationNamesParameter {
87      get { return (ValueParameter<StringArray>)Parameters["LocationNames"]; }
88    }
89
90    public FixedValueParameter<DoubleValue> QualityParameter {
91      get { return (FixedValueParameter<DoubleValue>)Parameters["Quality"]; }
92    }
93
94    public ValueParameter<DoubleArray> QualitiesParameter {
95      get { return (ValueParameter<DoubleArray>)Parameters["Qualities"]; }
96    }
97    #endregion
98
99    #region Parameter Values
100    public StringArray LocationNames {
101      get { return LocationNamesParameter.Value; }
102      private set { LocationNamesParameter.Value = value; }
103    }
104
105    public double Quality {
106      get { return QualityParameter.Value.Value; }
107      private set { QualityParameter.Value.Value = value; }
108    }
109    public DoubleArray Qualities {
110      get { return QualitiesParameter.Value; }
111      private set { QualitiesParameter.Value = value; }
112    }
113    #endregion
114
115    private readonly Closure<GeometryFeatureProvider> geometry = new Closure<GeometryFeatureProvider>(Closure<GeometryFeatureProvider>.Encapsulation.Referenced);
116
117    [Storable]
118    public GeometryFeatureProvider Geometry { get { return geometry.Value; } private set { geometry.Value = value; } }
119
120    public event EventHandler SolutionChanged;
121
122    private void OnSolutionChanged() {
123      var handler = SolutionChanged;
124      if (handler != null)
125        handler(this, EventArgs.Empty);
126    }
127
128    private static bool IsSlimKey(string key) {
129      if (LayerDescriptor.Utilizations.IsSuffixOf(key)) return true;
130      if (LayerDescriptor.ConverterCapacities.IsSuffixOf(key)) return true;
131      if (LayerDescriptor.RelativeCostAtSource.IsSuffixOf(key)) return true;
132      return false;
133    }
134
135    #region Construction & Cloning
136    [StorableConstructor]
137    private BioBoostCompoundSolution(bool isDeserializing) : base(isDeserializing) { }
138    private BioBoostCompoundSolution(BioBoostCompoundSolution orig, Cloner cloner, bool full = true) : base(orig, cloner) {
139      problemDataRef = orig.problemDataRef; // doesn't re-evaluate the solution
140      Geometry = orig.Geometry;
141      Quality = orig.Quality;
142      Qualities = (DoubleArray) orig.Qualities.Clone();
143      IntValues = orig.IntValues.ToDictionary(kvp => kvp.Key, kvp => (IntArray) kvp.Value.Clone());
144      if (full) {
145        DoubleValues = orig.DoubleValues.ToDictionary(kvp => kvp.Key, kvp => (DoubleArray) kvp.Value.Clone());
146        StringValues = orig.StringValues.ToDictionary(kvp => kvp.Key, kvp => (StringArray) kvp.Value.Clone());
147        if (orig.TransportTargets != null)
148          TransportTargets = orig.TransportTargets.ToDictionary(kvp => kvp.Key, kvp => (ItemArray<ItemList<IntValue>>)kvp.Value.Clone());
149      } else {
150        DoubleValues = orig.DoubleValues.Where(kvp => IsSlimKey(kvp.Key)).ToDictionary(kvp => kvp.Key, kvp => (DoubleArray) kvp.Value.Clone());
151        StringValues = new Dictionary<string, StringArray>();
152        if (orig.TransportTargets != null)
153          TransportTargets = new Dictionary<string, ItemArray<ItemList<IntValue>>>();
154      }
155    }
156    private BioBoostCompoundSolution() {
157      Parameters.Add(new ValueParameter<StringArray>("LocationNames", "The names of the different locations."));
158      Parameters.Add(new FixedValueParameter<DoubleValue>("Quality", "The quality of the solution as produced by the evaluator.", new DoubleValue()));
159      Parameters.Add(new ValueParameter<DoubleArray>("Qualities", "The quality criteria of the solution as produced by the evaluator.", new DoubleArray()));
160      IntValues = new Dictionary<string, IntArray>();
161      DoubleValues = new Dictionary<string, DoubleArray>();
162      StringValues = new Dictionary<string, StringArray>();
163      TransportTargets = new Dictionary<string, ItemArray<ItemList<IntValue>>>();
164    }
165
166
167    private bool TryAddValue(IScope scope, string valueName) {
168      IVariable var;
169      if (!scope.Variables.TryGetValue(valueName, out var))
170        return false;
171      var doubleArray = var.Value as DoubleArray;
172      if (doubleArray != null && !DoubleValues.ContainsKey(valueName)) {
173        DoubleValues.Add(valueName, (DoubleArray) doubleArray.Clone());
174        return true;
175      }
176      var intArray = var.Value as IntArray;
177      if (intArray != null && !IntValues.ContainsKey(valueName)) {
178        IntValues.Add(valueName, (IntArray) intArray.Clone());
179        return true;
180      }
181      var stringArray = var.Value as StringArray;
182      if (stringArray != null && !StringValues.ContainsKey(valueName)) {
183        StringValues.Add(valueName, (StringArray) stringArray.Clone());
184        return true;
185      }
186      var itemArray = var.Value as ItemArray<ItemList<IntValue>>;
187      if (itemArray != null && !TransportTargets.ContainsKey(valueName)) {
188        TransportTargets.Add(valueName, (ItemArray<ItemList<IntValue>>) itemArray.Clone());
189      }
190      return false;
191    }
192
193    private bool TryAddValue(BioBoostProblemData problemData, string valueName) {
194      IParameter param;
195      if (problemData.FeedstockPotentials.TryGetValue(valueName, out param)) {
196        var valueParam = param as IValueParameter;
197        if (valueParam != null) {
198          var doubleArray = valueParam.Value as DoubleArray;
199          if (doubleArray != null && !DoubleValues.ContainsKey(valueName)) {
200            DoubleValues.Add(valueName, (DoubleArray) doubleArray.Clone());
201            return true;
202          }
203          var intArray = valueParam.Value as IntArray;
204          if (intArray != null && !IntValues.ContainsKey(valueName)) {
205            IntValues.Add(valueName, (IntArray) intArray.Clone());
206            return true;
207          }
208          var stringArray = valueParam.Value as StringArray;
209          if (stringArray != null && !StringValues.ContainsKey(valueName)) {
210            StringValues.Add(valueName, (StringArray) stringArray.Clone());
211            return true;
212          }
213          var itemArray = valueParam.Value as ItemArray<ItemList<IntValue>>;
214          if (itemArray != null && !TransportTargets.ContainsKey(valueName)) {
215            TransportTargets.Add(valueName, (ItemArray<ItemList<IntValue>>) itemArray.Clone());
216            return true;
217          }
218        }
219      }
220      return false;
221    }
222
223    public BioBoostCompoundSolution(IScope scope, BioBoostProblemData problemData) : this() {
224      this.problemDataRef = problemData; // not cloned on purpose
225      Geometry = problemData.Geometry; // TODO: maybe clone geometry once?
226      LocationNames = (StringArray)problemData.LocationNames.Clone();
227      IVariable qualityVariable;
228      // TotalCost is the quality produced by the aggregate evaluator
229      if (scope.Variables.TryGetValue("TotalCost", out qualityVariable)) {
230        Quality = ((DoubleValue) qualityVariable.Value).Value; // TODO: should be read only
231      } else if (scope.Variables.TryGetValue("Quality", out qualityVariable)) {
232        Quality = ((DoubleValue) qualityVariable.Value).Value; // TODO: should be read only
233      }
234      if (scope.Variables.TryGetValue("QualityCriteria", out qualityVariable)) {
235        Qualities = (DoubleArray) qualityVariable.Value.Clone(); // TODO: should be read only
236      }
237      var isUpgradedSolution = scope.Variables.Any(v => v.Name.Contains(LayerDescriptor.AmountsAtSource.FullName));
238      foreach (var p in problemData.Products) {
239        if (!isUpgradedSolution) {
240          if (TryAddValue(scope, LayerDescriptor.TransportTargets.NameWithPrefix(p.Label)))
241            TryAddValue(scope, LayerDescriptor.Utilizations.NameWithPrefix(p.Label));
242        } else {
243          TryAddValue(problemData, LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(p.Label));
244          TryAddValue(scope, p.Label); // emissions
245          foreach (var layer in LayerDescriptor.Layers) { TryAddValue(scope, layer.NameWithPrefix(p.Label)); }
246        }
247      }
248      if (isUpgradedSolution)
249        foreach (var layer in LayerDescriptor.Layers) { TryAddValue(scope, layer.Name); }
250    }
251
252    public override IDeepCloneable Clone(Cloner cloner) {
253      return new BioBoostCompoundSolution(this, cloner);
254    }
255    public BioBoostCompoundSolution SlimClone() {
256      return new BioBoostCompoundSolution(this, new Cloner(), false);
257    }
258    [StorableHook(HookType.AfterDeserialization)]
259    private void AfterDeserialization() {
260      if (StringValues == null)
261        StringValues = new Dictionary<string, StringArray>();
262      // backwards compatibility
263      if (!Parameters.ContainsKey("Quality"))
264        Parameters.Add(new FixedValueParameter<DoubleValue>("Quality", new DoubleValue(double.NaN))); // TODO: use different quality value to indicate that the value is not known?
265      if(!Parameters.ContainsKey("Qualities"))
266        Parameters.Add(new ValueParameter<DoubleArray>("Qualities", "The quality criteria of the solution as produced by the evaluator.", new DoubleArray()));
267    }
268    #endregion
269
270    public void UpdateTo(BioBoostCompoundSolution bestSolution) {
271      if (LocationNames.SequenceEqual(bestSolution.LocationNames)) { // TODO: replace with comparison of problem reference
272        Quality = bestSolution.Quality;
273        Qualities = (DoubleArray) bestSolution.Qualities.Clone();
274        IntValues = bestSolution.IntValues.ToDictionary(kvp => kvp.Key, kvp => (IntArray)kvp.Value.Clone());
275        DoubleValues = bestSolution.DoubleValues.ToDictionary(kvp => kvp.Key, kvp => (DoubleArray)kvp.Value.Clone());
276        StringValues = bestSolution.StringValues.ToDictionary(kvp => kvp.Key, kvp => (StringArray)kvp.Value.Clone());
277        TransportTargets = bestSolution.TransportTargets.ToDictionary(kvp => kvp.Key, kvp => (ItemArray<ItemList<IntValue>>)kvp.Value.Clone());
278        OnSolutionChanged();
279      } else {
280        throw new ArgumentException("Invalid solution update, proposed solution has different problem instance.");
281      }
282    }
283
284    public static DoubleArray FindAmountsTransportedFromSource(IEnumerable<KeyValuePair<string, DoubleArray>> dict, string productName) {
285      if (LayerDescriptor.TransportTargets.IsSuffixOf(productName))
286        productName = LayerDescriptor.TransportTargets.RemoveSuffixFrom(productName);
287      foreach (var kvp in dict) {
288        if (LayerDescriptor.AmountsTransportedFromSource.IsSuffixOf(kvp.Key) &&
289          LayerDescriptor.AmountsTransportedFromSource.RemoveSuffixFrom(kvp.Key) == productName)
290          return kvp.Value;
291      }
292      return null;
293    }
294
295    #region convenience methods for retrieving values
296
297    public double TotalFeedstockCosts {
298      get {
299        // first get the list of feedstock (all products which are utilized)
300        var feedStockLabels =
301          DoubleValues.Keys
302            .Where(k => LayerDescriptor.Utilizations.IsSuffixOf(k))
303            .Select(k => LayerDescriptor.Utilizations.RemoveSuffixFrom(k));
304
305        return feedStockLabels
306          .Select(feedstock => DoubleValues[LayerDescriptor.TotalCostsAtSource.NameWithPrefix(feedstock)].Sum()) // sum over regions           
307          .Sum(); // sum over feedstock
308      }
309    }
310
311    public double TotalTransportCosts {
312      get {
313        // here we add transport and handling costs
314        // keys for all transport costs end with BioBoostProblem.TransportCostsName
315        // keys for all handling costs end with BioBoostProblem.HandlingCostsName
316        return DoubleValues
317          .Where(kvp => LayerDescriptor.TransportCosts.IsSuffixOf(kvp.Key) || LayerDescriptor.HandlingCosts.IsSuffixOf(kvp.Key))
318          .Select(kvp => kvp.Value.Sum()) // sum over all regions
319          .Sum(); // sum over all products
320      }
321    }
322
323    public double TotalCosts {
324      get {
325        // we add all costs (including all revenues from selling products)
326        // assumes that revenues are also labeled as costs!
327        return DoubleValues
328          .Where(kvp => kvp.Key.EndsWith("Cost") || kvp.Key.EndsWith("Costs"))
329          .Sum(kvp => kvp.Value.Where(v => v > 0).Sum());  // sum over products and regions
330      }
331    }
332
333    public double TotalTransportFuelAmount {
334      get {
335        // assumes that the values are stored as  "TransportFuel" + BioBoostProblem.AmountsAtSourceName
336        return DoubleValues
337          .Where(kvp => kvp.Key == LayerDescriptor.AmountsAtSource.NameWithPrefix("TransportFuel"))
338          .Sum(kvp => kvp.Value.Sum());
339      }
340    }
341
342    public IEnumerable<TransportInfo> Transports {
343      get {
344        foreach (var pair in TransportVectors) {
345          var prod = pair.Item1;
346          var modes = StringValues[LayerDescriptor.TransportModes.NameWithPrefix(prod)];
347          var distances = DoubleValues[LayerDescriptor.TransportDistance.NameWithPrefix(prod)];
348          var amounts = DoubleValues[LayerDescriptor.AmountsTransportedFromSource.NameWithPrefix(prod)];
349          for (int srcIdx = 0; srcIdx < pair.Item2.Length; srcIdx++) {
350            var destIdx = pair.Item2[srcIdx];
351            if (destIdx == -1) continue;
352            var info = new TransportInfo {
353              Product = prod,
354              SrcRegionIdx = srcIdx,
355              DestRegionIdx = destIdx,
356              SrcRegion = LocationNames[srcIdx],
357              DestRegion = LocationNames[destIdx],
358              Mode = modes[srcIdx],
359              Distance = distances[srcIdx],
360              Amount = amounts[srcIdx]
361            };
362            yield return info;
363          }
364        }
365      }
366    }
367
368    public IEnumerable<Tuple<string, int[]>> TransportVectors {
369      get {
370        // here we yield one tuple for each product containing the product name and transport target map
371        // we know transport targets are int-arrays and the key ends with 'BioBoostProblem.TransportTargetsName'
372        foreach (var p in IntValues.Where(p => LayerDescriptor.TransportTargets.IsSuffixOf(p.Key))) {
373          var productLabel = LayerDescriptor.TransportTargets.RemoveSuffixFrom(p.Key);
374          yield return Tuple.Create(productLabel, p.Value.ToArray());
375        }
376      }
377    }
378
379    public IEnumerable<Tuple<string, double[]>> UtilizationVectors {
380      get {
381        // here we yield one tuple for each feedstock containing the feedstock name and the utilization factor
382        // we know feedstock utilizations are double-arrays and the key ends with 'BioBoostProblem.UtilizationsName'
383        foreach (var p in DoubleValues.Where(p => LayerDescriptor.Utilizations.IsSuffixOf(p.Key))) {
384          var productLabel = LayerDescriptor.Utilizations.RemoveSuffixFrom(p.Key);
385          yield return Tuple.Create(productLabel, p.Value.ToArray());
386        }
387      }
388    }
389
390    public double GetUtilization(string feedstock, string currentRegion) {
391      return DoubleValues[LayerDescriptor.Utilizations.NameWithPrefix(feedstock)][IndexOfLoc(currentRegion)];
392    }
393
394    public void SetUtilization(string feedstock, string currentRegion, double newUtil) {
395      SetUtilization(feedstock, IndexOfLoc(currentRegion), newUtil);
396    }
397    public void SetUtilization(string feedstock, int regionIdx, double newUtil) {
398      DoubleValues[LayerDescriptor.Utilizations.NameWithPrefix(feedstock)][regionIdx] = newUtil;
399      EvaluateAndUpdateAllResults();
400    }
401
402    public void SetTransport(string product, int srcIdx, int destIdx) {
403      IntValues[LayerDescriptor.TransportTargets.NameWithPrefix(product)][srcIdx] = destIdx;
404      EvaluateAndUpdateAllResults();
405    }
406    public void SetTransport(string product, string srcNuts, string destNuts) {
407      SetTransport(product, IndexOfLoc(srcNuts), IndexOfLoc(destNuts));
408    }
409
410    public void EvaluateAndUpdateAllResults() {
411      if (problemDataRef == null) {
412        // for old persisted problems
413        throw new NotSupportedException("The problem data has not been set for this solution. Editing and re-evaluation is not possible");
414      }
415      var evalScope = AggregateEvaluator.Evaluate(
416        problemDataRef,
417        DoubleValues.Where(kvp => LayerDescriptor.Utilizations.IsSuffixOf(kvp.Key)),
418        IntValues.Where(kvp => LayerDescriptor.TransportTargets.IsSuffixOf(kvp.Key))
419        );
420
421      var newSolution = new BioBoostCompoundSolution(evalScope, problemDataRef);
422      this.UpdateTo(newSolution);
423    }
424
425    private int IndexOfLoc(string locationName) {
426      for (int i = 0; i < LocationNames.Length; i++) {
427        if (LocationNames[i] == locationName) return i;
428      }
429      return -1;
430    }
431    #endregion
432
433    public override void CollectParameterValues(IDictionary<string, IItem> values) {
434      base.CollectParameterValues(values);
435
436      // also produce additional values (virtual parameters) for most important results
437      foreach (var kvp in DoubleValues) {
438        var vFiltered = kvp.Value.Where(x => x > 0);
439        if (!vFiltered.Any()) continue;
440
441        if (kvp.Key.Contains("Relative") || kvp.Key.Contains("Capacities")) {
442          values.Add(kvp.Key + " (min)", new DoubleValue(vFiltered.Min()));
443          values.Add(kvp.Key + " (max)", new DoubleValue(vFiltered.Max()));
444          values.Add(kvp.Key + " (avg)", new DoubleValue(vFiltered.Average()));
445        } else if (kvp.Key.Contains("Utilization")) {
446          values.Add(kvp.Key + " (count)", new DoubleValue(vFiltered.Count())); // |{u | u > 0}|
447          values.Add(kvp.Key + " (avg)", new DoubleValue(vFiltered.Average()));
448        } else if (!kvp.Key.Contains("Potentials")) {
449          values.Add(kvp.Key + " (sum)", new DoubleValue(kvp.Value.Sum()));
450          values.Add(kvp.Key + " (count)", new DoubleValue(vFiltered.Count()));
451          values.Add(kvp.Key + " (min)", new DoubleValue(vFiltered.Min()));
452          values.Add(kvp.Key + " (max)", new DoubleValue(vFiltered.Max()));
453          values.Add(kvp.Key + " (avg)", new DoubleValue(vFiltered.Average()));
454        }
455      }
456
457      var finalProductNames = DoubleValues.Keys.Where(k => LayerDescriptor.AmountsAtSource.IsSuffixOf(k))
458        .Select(k => LayerDescriptor.AmountsAtSource.RemoveSuffixFrom(k));
459      finalProductNames = finalProductNames
460        .Where(k => DoubleValues.ContainsKey(LayerDescriptor.DischargeCosts.NameWithPrefix(k)) &&
461                    DoubleValues[LayerDescriptor.DischargeCosts.NameWithPrefix(k)].Sum() < 0);
462
463      foreach (var finalProductName in finalProductNames) {
464        var costs = DoubleValues
465          .Where(kvp => !kvp.Key.StartsWith(finalProductName))
466          .Where(kvp => kvp.Key.EndsWith("Costs") || kvp.Key.EndsWith("Cost"))
467          .Select(kvp => kvp.Value.Sum())
468          .Sum();
469
470        var amount = DoubleValues[LayerDescriptor.AmountsAtSource.NameWithPrefix(finalProductName)].Sum();
471
472        values.Add(finalProductName + " net cost [€/a]", new DoubleValue(costs));
473        values.Add(finalProductName + " net cost [€/t]", new DoubleValue(costs / amount));
474      }
475    }
476
477
478    public double PerformPostProcessing(TextWriter logger = null) {
479      // DeletePenalizedFeedstockTransportsUtilizations();
480      // DeletePlantsWithScalingFactorBelow(0.8, feedstockName);
481      // DeletePlantsWithScalingFactorBelow(0.8, intermediateName);
482      // DeleteEmptyPlants(intermediateName); // maybe this is covered by previous functions?
483      string feedstockName = null, intermediateName = null;
484      IDictionary<int, int[]> decentralPlantSources = null, centralPlantSources = null;
485      foreach (var transportTargets in IntValues.Where(kvp => LayerDescriptor.TransportTargets.IsSuffixOf(kvp.Key))) {
486        var name = LayerDescriptor.TransportTargets.RemoveSuffixFrom(transportTargets.Key);
487        var utilizationLayerName = LayerDescriptor.Utilizations.NameWithPrefix(name);
488        var utilizationsKvp = DoubleValues.FirstOrDefault(kvp => kvp.Key == utilizationLayerName);
489        if (utilizationsKvp.Key != null) {
490          feedstockName = name;
491          decentralPlantSources = transportTargets.Value.SourceIndices();
492        } else {
493          intermediateName = name;
494          centralPlantSources = transportTargets.Value.SourceIndices();
495        }
496      }
497      if (feedstockName == null || intermediateName == null || decentralPlantSources == null ||
498          centralPlantSources == null)
499        throw new Exception("Post Processing Failed");
500
501      var utilizations =
502        DoubleValues.First(kvp => kvp.Key == LayerDescriptor.Utilizations.NameWithPrefix(feedstockName)).Value;
503      var feedstockUsageBefore =
504        utilizations.Zip(
505          (DoubleArray) ((IValueParameter) problemDataRef.FeedstockPotentials[feedstockName + "Potentials"]).Value,
506          (u, p) => u*p).Sum();
507
508      // remove penalized transports
509      var feedstockTransportPenaltyLayer =
510        DoubleValues.First(
511          kvp => kvp.Key == LayerDescriptor.ExceedingTransportDistancePenalty.NameWithPrefix(feedstockName)).Value;
512      var removableSuppliers = feedstockTransportPenaltyLayer
513        .Select((penalty, idx) => new {penalty, idx})
514        .Where(pi => pi.penalty > 0)
515        .Select(pi => new List<int> {pi.idx}).ToList();
516
517      // remove undersize central plants
518      var centralConversion = ProblemDataReference.Conversions[feedstockName].First();
519      var minCentralScalingFactor = centralConversion.MinCapacity/centralConversion.DesignCapacity;
520      var centralScalingFactors =
521        DoubleValues.First(kvp => kvp.Key == LayerDescriptor.ScalingFactors.NameWithPrefix(intermediateName)).Value;
522      removableSuppliers.AddRange(centralScalingFactors
523        .Select((factor, idx) => new {factor, idx})
524        .Where(fi => fi.factor < minCentralScalingFactor)
525        .Select(fi => GetSuppliers(new[] {centralPlantSources, decentralPlantSources}, fi.idx).ToList())
526        .Where(l => l.Count > 0));
527
528      // remove undersize decentral plants
529      var decentralConversion = ProblemDataReference.Conversions[intermediateName].First();
530      var minDeCentralScalingFactor = decentralConversion.MinCapacity/decentralConversion.DesignCapacity;
531      var decentralScalingFactors =
532        DoubleValues.First(kvp => kvp.Key == LayerDescriptor.ScalingFactors.NameWithPrefix(feedstockName)).Value;
533      removableSuppliers.AddRange(decentralScalingFactors
534        .Select((factor, idx) => new {factor, idx})
535        .Where(fi => fi.factor < minDeCentralScalingFactor)
536        .Select(fi => GetSuppliers(new[] {decentralPlantSources}, fi.idx).ToList())
537        .Where(l => l.Count > 0));
538
539      EvaluateAndUpdateAllResults();
540      if (logger != null) logger.Write("Pruning plants (q={0})...", Quality);
541      int successes = 0;
542      int k = 0, lastK = 0;
543      foreach (var variant in removableSuppliers) {
544        var oldUtilizations = (DoubleArray)utilizations.Clone();
545        var oldQuality = Quality;
546        foreach (int j in variant) utilizations[j] = 0;
547        DoubleValues.Remove(LayerDescriptor.Utilizations.NameWithPrefix(feedstockName));
548        DoubleValues.Add(LayerDescriptor.Utilizations.NameWithPrefix(feedstockName), utilizations);
549        EvaluateAndUpdateAllResults();
550        if (Quality < oldQuality) {
551          for (int i = 0; i<utilizations.Length; i++) utilizations[i] = oldUtilizations[i];
552          DoubleValues.Remove(LayerDescriptor.Utilizations.NameWithPrefix(feedstockName));
553          DoubleValues.Add(LayerDescriptor.Utilizations.NameWithPrefix(feedstockName), utilizations);
554        } else {
555          successes++;
556        }
557        if (k++ > lastK + removableSuppliers.Count/20 && logger != null) {
558          logger.Write("{0}%...", k*100/removableSuppliers.Count);
559          lastK = k;
560        }
561      }
562      EvaluateAndUpdateAllResults();
563      if (logger != null) logger.WriteLine("... pruned {0} of {1} variants (q={2})", successes, removableSuppliers.Count, Quality);
564
565      var feedstockUsageAfter =
566        utilizations.Zip((DoubleArray) ((IValueParameter) problemDataRef.FeedstockPotentials[feedstockName + "Potentials"]).Value,
567          (u, p) => u*p).Sum();
568      var utilizationFactor = feedstockUsageAfter/feedstockUsageBefore;
569      return utilizationFactor;
570    }
571
572    public static IEnumerable<int> GetSuppliers(IEnumerable<IDictionary<int, int[]>> suppliers, int i) {
573      throw new NotImplementedException();  // waiting for source for DictionaryExtensions
574      //       var lists = suppliers.ToList();
575//       switch (lists.Count) {
576//         case 0: {
577//           yield break;
578//         }
579//         case 1: {
580//           foreach (var j in lists[0].ElementAtOrDefault(i, new int[0]))
581//             yield return j;
582//           break;
583//         }
584//         default: {
585//           foreach (
586//             var x in lists[0].ApplyAt(i,
587//                 v => v.Select(j => GetSuppliers(lists.Skip(1), j))
588//                       .Aggregate(Enumerable.Empty<int>(), (l1, l2) => l1.Concat(l2)),
589//                 () => new int[0]))
590//             yield return x;
591//           break;
592//         }
593//       }
594    }
595
596    #region unused
597    public void CreateJsonSolution() {
598      var builder = new StringBuilder();
599      builder.Append("{ \"type\": \"FeatureCollection\", \n\"features\": [");
600      for (int i = 0; i < LocationNames.Length; i++) {
601        if (i > 0) builder.Append(",");
602        builder.Append("\n{ \"type\": \"Feature\", \"properties\": { \"NUTS_ID\": \"");
603        builder.Append(LocationNames[i]);
604        builder.Append("\"");
605        foreach (var kvp in IntValues) {
606          var target = LocationNames[i];
607          if (kvp.Value[i] >= 0) {
608            target = LocationNames[kvp.Value[i]];
609          }
610          builder.Append(",\n                                     \"");
611          builder.Append(kvp.Key);
612          builder.Append("\": \"");
613          builder.Append(target);
614          builder.Append("\"");
615        }
616        foreach (var kvp in DoubleValues) {
617          builder.Append(",\n                                     \"");
618          builder.Append(kvp.Key);
619          builder.Append("\": ");
620          builder.Append(kvp.Value[i].ToString("R", CultureInfo.InvariantCulture));
621        }
622        builder.Append("} }");
623      }
624      builder.Append("\n]\n}");
625
626      File.WriteAllText(@"c:\temp\test.json", builder.ToString());
627    }
628    #endregion
629
630    public string Filename { get; set; }
631  }
632}
Note: See TracBrowser for help on using the repository browser.