package org.openlca.geo; import java.util.Map; import java.util.function.BiConsumer; import org.openlca.core.database.IDatabase; import org.openlca.core.math.CalculationSetup; import org.openlca.core.math.DataStructures; import org.openlca.core.math.IMatrix; import org.openlca.core.math.IMatrixSolver; import org.openlca.core.math.LcaCalculator; import org.openlca.core.matrix.CostVector; import org.openlca.core.matrix.ImpactTable; import org.openlca.core.matrix.Inventory; import org.openlca.core.matrix.InventoryMatrix; import org.openlca.core.matrix.LongPair; import org.openlca.core.matrix.ParameterTable; import org.openlca.core.matrix.cache.MatrixCache; import org.openlca.core.results.FullResult; import org.openlca.core.results.LinkContributions; import org.openlca.expressions.FormulaInterpreter; import org.openlca.expressions.Scope; import org.openlca.geo.kml.LocationKml; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RegionalizedCalculator { private Logger log = LoggerFactory.getLogger(getClass()); private final CalculationSetup setup; private final IMatrixSolver solver; public RegionalizedCalculator(CalculationSetup setup, IMatrixSolver solver) { this.setup = setup; this.solver = solver; } public RegionalizedResult calculate(IDatabase db, MatrixCache cache) { return calculate(db, cache, null); } public RegionalizedResult calculate(IDatabase db, MatrixCache cache, RegionalizationSetup regioSetup) { try { Inventory inventory = DataStructures.createInventory(setup, cache); if (regioSetup == null) regioSetup = RegionalizationSetup.create(db, setup.impactMethod, inventory.productIndex); if (!regioSetup.canCalculate) return null; ParameterTable parameterTable = DataStructures .createParameterTable(regioSetup.database, setup, inventory); FormulaInterpreter interpreter = parameterTable.createInterpreter(); InventoryMatrix m = inventory.createMatrix( solver.getMatrixFactory(), interpreter); ImpactTable impactTable = ImpactTable.build(cache, setup.impactMethod.getId(), inventory.flowIndex); FullResult r = new FullResult(); r.flowIndex = inventory.flowIndex; r.productIndex = inventory.productIndex; r.impactIndex = impactTable.categoryIndex; // direct LCI results LcaCalculator baseCalc = new LcaCalculator(solver, m); IMatrix inverse = solver.invert(m.technologyMatrix); r.scalingFactors = baseCalc.getScalingVector(inverse, r.productIndex); r.singleFlowResults = m.interventionMatrix.copy(); solver.scaleColumns(r.singleFlowResults, r.scalingFactors); r.totalRequirements = baseCalc.getTotalRequirements( m.technologyMatrix, r.scalingFactors); r.linkContributions = LinkContributions.calculate(m.technologyMatrix, m.productIndex, r.scalingFactors); // assessed intervention matrix IMatrix factors = impactTable.createMatrix( solver.getMatrixFactory(), interpreter).factorMatrix; r.impactFactors = factors; IMatrix assessedEnvi = solver.multiply(factors, m.interventionMatrix); eachKml(regioSetup, impactTable, interpreter, (kml, kmlFactors) -> { IMatrix assessedKml = solver.multiply(kmlFactors, m.interventionMatrix); for (LongPair product : kml.processProducts) { int col = r.productIndex.getIndex(product); for (int row = 0; row < assessedEnvi.rows(); row++) { assessedEnvi.set(row, col, assessedKml.get(row, col)); } } }); // direct LCIA results r.singleImpactResults = assessedEnvi.copy(); solver.scaleColumns(r.singleImpactResults, r.scalingFactors); // upstream & total results double[] demands = baseCalc.getRealDemands(r.totalRequirements, r.productIndex); r.upstreamFlowResults = solver.multiply(m.interventionMatrix, inverse); solver.scaleColumns(r.upstreamFlowResults, demands); r.upstreamImpactResults = solver.multiply(assessedEnvi, inverse); solver.scaleColumns(r.upstreamImpactResults, demands); int refIdx = r.productIndex.getIndex(r.productIndex.getRefFlow()); r.totalFlowResults = r.upstreamFlowResults.getColumn(refIdx); r.totalImpactResults = r.upstreamImpactResults.getColumn(refIdx); // add LCC results if (setup.withCosts) { r.hasCostResults = true; CostVector costVector = CostVector.build(inventory, db); // direct LCC double[] costValues = costVector.values; double[] directCosts = new double[costValues.length]; for (int i = 0; i < r.scalingFactors.length; i++) { directCosts[i] = costValues[i] * r.scalingFactors[i]; } r.singleCostResults = directCosts; // upstream LCC IMatrix costMatrix = costVector.asMatrix(solver.getMatrixFactory()); IMatrix upstreamCosts = solver.multiply(costMatrix, inverse); solver.scaleColumns(upstreamCosts, demands); r.totalCostResult = upstreamCosts.get(0, refIdx); r.upstreamCostResults = upstreamCosts; } return new RegionalizedResult(r, regioSetup.kmlData, regioSetup.parameterSet); } catch (Exception e) { log.error("failed to calculate regionalized result", e); return null; } } private void eachKml(RegionalizationSetup regioSetup, ImpactTable table, FormulaInterpreter interpreter, BiConsumer<LocationKml, IMatrix> fn) { Scope scope = interpreter.getScope(setup.impactMethod.getId()); for (LocationKml kml : regioSetup.kmlData) { Map<String, Double> params = regioSetup.parameterSet.get( kml.locationId); for (String param : params.keySet()) { Double val = params.get(param); if (val == null) continue; scope.bind(param, val.toString()); } IMatrix factors = table.createMatrix(solver.getMatrixFactory(), interpreter).factorMatrix; fn.accept(kml, factors); } } }