package org.openlca.core.math; import org.openlca.core.matrix.CostVector; import org.openlca.core.matrix.ImpactMatrix; import org.openlca.core.matrix.InventoryMatrix; import org.openlca.core.matrix.LongPair; import org.openlca.core.matrix.TechIndex; import org.openlca.core.results.ContributionResult; import org.openlca.core.results.FullResult; import org.openlca.core.results.LinkContributions; import org.openlca.core.results.SimpleResult; public class LcaCalculator { private final IMatrixSolver solver; private final InventoryMatrix inventory; private ImpactMatrix impactMatrix; private CostVector costVector; public LcaCalculator(IMatrixSolver solver, InventoryMatrix inventory) { this.solver = solver; this.inventory = inventory; } public void setImpactMatrix(ImpactMatrix impactMatrix) { this.impactMatrix = impactMatrix; } public void setCostVector(CostVector costVector) { this.costVector = costVector; } public SimpleResult calculateSimple() { SimpleResult result = new SimpleResult(); result.flowIndex = inventory.flowIndex; result.productIndex = inventory.productIndex; IMatrix techMatrix = inventory.technologyMatrix; TechIndex productIndex = inventory.productIndex; int idx = productIndex.getIndex(productIndex.getRefFlow()); double[] s = solver.solve(techMatrix, idx, productIndex.getDemand()); result.scalingFactors = s; result.totalRequirements = getTotalRequirements(techMatrix, s); IMatrix enviMatrix = inventory.interventionMatrix; result.totalFlowResults = solver.multiply(enviMatrix, s); if (impactMatrix != null) { addTotalImpacts(result); } if (costVector != null) { result.hasCostResults = true; addTotalCosts(result, s); } return result; } public ContributionResult calculateContributions() { ContributionResult result = new ContributionResult(); result.flowIndex = inventory.flowIndex; result.productIndex = inventory.productIndex; IMatrix techMatrix = inventory.technologyMatrix; TechIndex productIndex = inventory.productIndex; int idx = productIndex.getIndex(productIndex.getRefFlow()); double[] s = solver.solve(techMatrix, idx, productIndex.getDemand()); result.scalingFactors = s; result.totalRequirements = getTotalRequirements(techMatrix, s); IMatrix enviMatrix = inventory.interventionMatrix; IMatrix singleResult = enviMatrix.copy(); solver.scaleColumns(singleResult, s); result.singleFlowResults = singleResult; result.totalFlowResults = solver.multiply(enviMatrix, s); result.linkContributions = LinkContributions.calculate( techMatrix, productIndex, s); if (impactMatrix != null) { addTotalImpacts(result); addDirectImpacts(result); } if (costVector != null) { result.hasCostResults = true; addTotalCosts(result, s); addDirectCosts(result, s); } return result; } public FullResult calculateFull() { FullResult result = new FullResult(); result.flowIndex = inventory.flowIndex; result.productIndex = inventory.productIndex; TechIndex productIdx = inventory.productIndex; IMatrix techMatrix = inventory.technologyMatrix; IMatrix enviMatrix = inventory.interventionMatrix; IMatrix inverse = solver.invert(techMatrix); double[] scalingVector = getScalingVector(inverse, productIdx); result.scalingFactors = scalingVector; // direct results IMatrix singleResult = enviMatrix.copy(); solver.scaleColumns(singleResult, scalingVector); result.singleFlowResults = singleResult; result.totalRequirements = getTotalRequirements(techMatrix, scalingVector); // upstream results double[] demands = getRealDemands(result.totalRequirements, productIdx); IMatrix totalResult = solver.multiply(enviMatrix, inverse); if (costVector == null) inverse = null; // allow GC solver.scaleColumns(totalResult, demands); result.upstreamFlowResults = totalResult; int refIdx = productIdx.getIndex(productIdx.getRefFlow()); result.totalFlowResults = totalResult.getColumn(refIdx); result.linkContributions = LinkContributions.calculate( techMatrix, productIdx, scalingVector); if (impactMatrix != null) { addDirectImpacts(result); IMatrix factors = impactMatrix.factorMatrix; IMatrix totalImpactResult = solver.multiply(factors, totalResult); result.upstreamImpactResults = totalImpactResult; // total impacts = upstream result of reference product result.impactIndex = impactMatrix.categoryIndex; result.totalImpactResults = totalImpactResult.getColumn(refIdx); } if (costVector != null) { result.hasCostResults = true; addDirectCosts(result, scalingVector); IMatrix costValues = costVector.asMatrix(solver.getMatrixFactory()); IMatrix upstreamCosts = solver.multiply(costValues, inverse); solver.scaleColumns(upstreamCosts, demands); result.totalCostResult = upstreamCosts.get(0, refIdx); result.upstreamCostResults = upstreamCosts; } return result; } /** * Calculates the scaling vector for the reference product i from the given * inverse of the technology matrix: * * s = d[i] .* Inverse[:, i] * * where d is the demand vector and. * */ public double[] getScalingVector(IMatrix inverse, TechIndex productIdx) { LongPair refProduct = productIdx.getRefFlow(); int idx = productIdx.getIndex(refProduct); double[] s = inverse.getColumn(idx); double demand = productIdx.getDemand(); for (int i = 0; i < s.length; i++) s[i] *= demand; return s; } /** * Calculates the total requirements of the respective product amounts to * fulfill the demand of the product system: * * tr = s .* diag(A) * * where s is the scaling vector and A the technology matrix. * */ public double[] getTotalRequirements(IMatrix techMatrix, double[] scalingVector) { double[] tr = new double[scalingVector.length]; for (int i = 0; i < scalingVector.length; i++) { tr[i] = scalingVector[i] * techMatrix.get(i, i); } return tr; } /** * Calculate the real demand vector for the analysis. */ public double[] getRealDemands(double[] totalRequirements, TechIndex productIdx) { double refDemand = productIdx.getDemand(); int i = productIdx.getIndex(productIdx.getRefFlow()); double[] rd = new double[totalRequirements.length]; if (Math.abs(totalRequirements[i] - refDemand) > 1e-9) { // 'self-loop' correction for total result scale double f = refDemand / totalRequirements[i]; for (int k = 0; k < totalRequirements.length; k++) rd[k] = f * totalRequirements[k]; } else { int length = totalRequirements.length; System.arraycopy(totalRequirements, 0, rd, 0, length); } return rd; } private void addTotalImpacts(SimpleResult result) { result.impactIndex = impactMatrix.categoryIndex; IMatrix factors = impactMatrix.factorMatrix; double[] totals = solver.multiply(factors, result.totalFlowResults); result.totalImpactResults = totals; } private void addDirectImpacts(ContributionResult result) { IMatrix factors = impactMatrix.factorMatrix; result.impactFactors = factors; IMatrix directResults = solver.multiply(factors, result.singleFlowResults); result.singleImpactResults = directResults; IMatrix singleFlowImpacts = factors.copy(); solver.scaleColumns(singleFlowImpacts, result.totalFlowResults); result.singleFlowImpacts = singleFlowImpacts; } private void addTotalCosts(SimpleResult result, double[] scalingVector) { double[] costValues = costVector.values; double total = 0; for (int i = 0; i < scalingVector.length; i++) { total += scalingVector[i] * costValues[i]; } result.totalCostResult = total; } private void addDirectCosts(ContributionResult result, double[] scalingVector) { double[] costValues = costVector.values; double[] directCosts = new double[costValues.length]; for (int i = 0; i < scalingVector.length; i++) { directCosts[i] = costValues[i] * scalingVector[i]; } result.singleCostResults = directCosts; } }