package org.openlca.core.results;
import java.util.HashMap;
import org.openlca.core.math.IMatrix;
import org.openlca.core.matrix.LongPair;
import org.openlca.core.matrix.TechIndex;
import org.openlca.core.model.ProcessLink;
/**
* Calculates the contributions of process products that are inputs in other
* processes. If a process product is input of only one process it's
* contribution to this process is 100%, whereas this contribution is split into
* the respective shares if this product goes into multiple processes. For
* example, if we have a process product p that goes with 5 kg into process x
* and with 3 kg into process y the contribution share of product p to process x
* is 5/8 = 62.5% and to process y 3/8 = 37.5%.
*/
public class LinkContributions {
/**
* Maps product links to shares: output-process-product -> input-process ->
* share.
*/
private HashMap<LongPair, HashMap<Long, Double>> shares = new HashMap<>();
private LinkContributions() {
}
public static LinkContributions calculate(IMatrix technologyMatrix,
TechIndex index, double[] scalingFactors) {
LinkContributions contributions = new LinkContributions();
contributions.calculateShares(technologyMatrix, index, scalingFactors);
return contributions;
}
/**
* Get the contribution share of the outgoing process product (provider) to
* the product input (recipient) of the given link and the calculated
* product system. The returned share is a value between 0 and 1.
*/
public double getShare(ProcessLink link) {
if (link == null)
return 0;
LongPair output = new LongPair(link.providerId, link.flowId);
HashMap<Long, Double> map = shares.get(output);
if (map == null)
return 0;
Double share = map.get(link.processId);
return share == null ? 0 : share;
}
double getShare(LongPair provider, LongPair recipient) {
if (provider == null || provider == null)
return 0;
HashMap<Long, Double> map = shares.get(provider);
if (map == null)
return 0;
Double share = map.get(recipient.getFirst());
return share == null ? 0 : share;
}
private void calculateShares(IMatrix matrix, TechIndex index,
double[] scalingFactors) {
for (int i = 0; i < index.size(); i++) {
LongPair outProduct = index.getProviderAt(i);
double outVal = scalingFactors[i] * matrix.get(i, i);
if (outVal == 0)
continue;
for (int k = 0; k < index.size(); k++) {
if (k == i)
continue;
double rawInVal = matrix.get(i, k);
if (rawInVal == 0)
continue;
double contr = -(scalingFactors[k] * rawInVal) / outVal;
LongPair inProduct = index.getProviderAt(k);
putShare(outProduct, inProduct, contr);
}
}
}
private void putShare(LongPair output, LongPair input, double share) {
HashMap<Long, Double> map = shares.get(output);
if (map == null) {
map = new HashMap<>();
shares.put(output, map);
}
Long inputProcess = input.getFirst();
Double oldShare = map.get(inputProcess);
if (oldShare == null)
map.put(inputProcess, share);
else {
double newShare = oldShare + share;
if (newShare < 1)
map.put(inputProcess, newShare);
else
map.put(inputProcess, 1d); // assert v <= 1
}
}
}