package org.openlca.app.editors.reports.model; import java.util.Collections; import java.util.Comparator; import java.util.Objects; import java.util.Set; import java.util.TreeSet; import org.openlca.app.App; import org.openlca.app.db.Cache; import org.openlca.app.db.Database; import org.openlca.app.editors.reports.model.ReportIndicatorResult.Contribution; import org.openlca.app.editors.reports.model.ReportIndicatorResult.VariantResult; import org.openlca.app.util.Numbers; import org.openlca.core.database.CurrencyDao; import org.openlca.core.math.ProjectCalculator; import org.openlca.core.matrix.NwSetTable; import org.openlca.core.model.Currency; import org.openlca.core.model.Project; import org.openlca.core.model.ProjectVariant; import org.openlca.core.model.descriptors.ImpactCategoryDescriptor; import org.openlca.core.model.descriptors.ProcessDescriptor; import org.openlca.core.results.ContributionItem; import org.openlca.core.results.ContributionSet; import org.openlca.core.results.ImpactResult; import org.openlca.core.results.ProjectResultProvider; import org.openlca.util.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ReportCalculator implements Runnable { private Logger log = LoggerFactory.getLogger(getClass()); private final Project project; private final Report report; public ReportCalculator(Project project, Report report) { this.project = project; this.report = report; } @Override public void run() { if (project == null || report == null) return; report.results.clear(); report.addedValues.clear(); report.netCosts.clear(); if (project.getImpactMethodId() == null) return; ProjectResultProvider projectResult = calcProject(project); if (projectResult == null) return; appendResults(projectResult); appendCostResults(projectResult); if (project.getNwSetId() != null) appendNwFactors(); } private ProjectResultProvider calcProject(Project project) { try { ProjectCalculator calculator = new ProjectCalculator( Cache.getMatrixCache(), App.getSolver()); return calculator.solve(project, Cache.getEntityCache()); } catch (Exception e) { log.error("Calculation of project failed", e); return null; } } private void appendNwFactors() { try { NwSetTable table = NwSetTable.build(Database.get(), project.getNwSetId()); report.withNormalisation = table.hasNormalisationFactors(); report.withWeighting = table.hasWeightingFactors(); for (ReportIndicator indicator : report.indicators) { if (indicator.descriptor == null) continue; long categoryId = indicator.descriptor.getId(); if (table.hasNormalisationFactors()) { double nf = table.getNormalisationFactor(categoryId); indicator.normalisationFactor = nf; } if (table.hasWeightingFactors()) { double wf = table.getWeightingFactor(categoryId); indicator.weightingFactor = wf; } } } catch (Exception e) { log.error("failed to load normalisation/weighting factors", e); } } private void appendResults(ProjectResultProvider result) { for (ImpactCategoryDescriptor impact : result.getImpactDescriptors()) { ReportIndicatorResult repResult = initReportResult(impact); if (repResult == null) continue; // should not add this indicator report.results.add(repResult); for (ProjectVariant variant : result.getVariants()) { VariantResult varResult = new VariantResult(); repResult.variantResults.add(varResult); varResult.variant = variant.getName(); ImpactResult impactResult = result.getTotalImpactResult( variant, impact); varResult.totalAmount = impactResult.value; ContributionSet<ProcessDescriptor> set = result .getResult(variant) .getProcessContributions(impact); appendProcessContributions(set, varResult); } } } private ReportIndicatorResult initReportResult(ImpactCategoryDescriptor impact) { for (ReportIndicator indicator : report.indicators) { if (!indicator.displayed) continue; if (Objects.equals(impact, indicator.descriptor)) return new ReportIndicatorResult(indicator.id); } return null; } private void appendProcessContributions( ContributionSet<ProcessDescriptor> set, VariantResult varResult) { Contribution rest = new Contribution(); varResult.contributions.add(rest); rest.rest = true; rest.processId = (long) -1; rest.amount = (double) 0; Set<Long> ids = getContributionProcessIds(); Set<Long> foundIds = new TreeSet<>(); for (ContributionItem<ProcessDescriptor> item : set.contributions) { if (item.item == null) continue; if (!ids.contains(item.item.getId())) rest.amount = rest.amount + item.amount; else { foundIds.add(item.item.getId()); addContribution(varResult, item); } } addDefaultContributions(ids, foundIds, varResult); } private void addContribution(VariantResult varResult, ContributionItem<ProcessDescriptor> item) { Contribution con = new Contribution(); varResult.contributions.add(con); con.amount = item.amount; con.rest = false; con.processId = item.item.getId(); } private Set<Long> getContributionProcessIds() { Set<Long> ids = new TreeSet<>(); for (ReportProcess process : report.processes) { if (process.descriptor == null) continue; ids.add(process.descriptor.getId()); } return ids; } /** * Add zero-contributions for processes that were not found in a variant * result. */ private void addDefaultContributions(Set<Long> ids, Set<Long> foundIds, VariantResult varResult) { TreeSet<Long> notFound = new TreeSet<>(ids); notFound.removeAll(foundIds); for (long id : notFound) { Contribution con = new Contribution(); varResult.contributions.add(con); con.amount = (double) 0; con.rest = false; con.processId = id; } } private void appendCostResults(ProjectResultProvider result) { if (result == null) return; String currency = getCurrency(); for (ProjectVariant var : result.getVariants()) { double costs = result.getResult(var).getTotalCostResult(); report.netCosts.add(cost(var, costs, currency)); double addedValue = costs == 0 ? 0 : -costs; report.addedValues.add(cost(var, addedValue, currency)); } Comparator<ReportCostResult> c = (r1, r2) -> { return Strings.compare(r1.variant, r2.variant); }; Collections.sort(report.netCosts, c); Collections.sort(report.addedValues, c); } private ReportCostResult cost(ProjectVariant var, double val, String cu) { ReportCostResult r = new ReportCostResult(); r.variant = var.getName(); r.value = Numbers.decimalFormat(val, 2) + " " + cu; return r; } private String getCurrency() { try { CurrencyDao dao = new CurrencyDao(Database.get()); Currency c = dao.getReferenceCurrency(); if (c == null) return "?"; return c.code != null ? c.code : c.getName(); } catch (Exception e) { log.error("failed to load default currency", e); return "?"; } } }